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 2009 Sun Microsystems, Inc.  All rights reserved.
  25 # Use is subject to license terms.
  26 #
  27 
  28 . $STF_TOOLS/include/stf.kshlib
  29 
  30 # Include common STC utility functions
  31 if [[ -s $STC_NFSUTILS/include/nfs-util.kshlib ]]; then
  32         . $STC_NFSUTILS/include/nfs-util.kshlib
  33 else
  34         . $STF_TMPDIR/nfs-util.kshlib
  35 fi
  36 
  37 NAME=$(basename $0)
  38 PATH=/usr/bin:/usr/sbin:$PATH; export PATH
  39 
  40 # Function to cleanup and exit
  41 #   Usage: cleanup exit_code
  42 #
  43 function cleanup {
  44         typeset Fname=cleanup
  45         [[ :$SHAREMNT_DEBUG: == *:$Fname:* \
  46                 || :$SHAREMNT_DEBUG: == *:all:* ]] && set -x
  47 
  48         rm -f $STF_TMPDIR/*.out.$$
  49         exit ${1}
  50 }
  51 
  52 # Function to generate option list with unique combination
  53 #   Usage: gen_opt_list the_option_array
  54 #   Return: the generated list
  55 #
  56 function gen_opt_list {
  57         typeset Fname=gen_opt_list
  58         [[ :$SHAREMNT_DEBUG: == *:$Fname:* \
  59                 || :$SHAREMNT_DEBUG: == *:all:* ]] && set -x
  60 
  61         typeset OPTLIST=${1}
  62         typeset GENERATE_LIST=""
  63         typeset -i length=$(echo $OPTLIST | wc -w)
  64         if (( length <= 1 )); then
  65                 GENERATE_LIST=$OPTLIST
  66         else
  67                 set - $OPTLIST
  68                 typeset item=$1 entry list
  69                 shift
  70                 list=$(gen_opt_list "$*")
  71                 for entry in $list; do
  72                         GENERATE_LIST="$GENERATE_LIST $item,$entry"
  73                 done
  74                 GENERATE_LIST="$GENERATE_LIST $item $list"
  75         fi
  76         echo $GENERATE_LIST
  77 }
  78 
  79 # Function to convert the form of options, currently including
  80 # ro, rw, and root, combining them with :
  81 #   Usage: convert_form the_option_array
  82 #   Return: the converted list
  83 #
  84 function convert_form {
  85         typeset Fname=convert_form
  86         [[ :$SHAREMNT_DEBUG: == *:$Fname:* \
  87                 || :$SHAREMNT_DEBUG: == *:all:* ]] && set -x
  88 
  89         typeset rolist rwlist rootlist optlist
  90         typeset opt
  91         for opt in $(echo $1 | sed 's/,/ /g'); do
  92                 [[ $opt == ro=* ]] && rolist=$rolist:${opt##ro=}
  93                 [[ $opt == rw=* ]] && rwlist=$rwlist:${opt##rw=}
  94                 [[ $opt == root=* ]] && rootlist=$rootlist:${opt##root=}
  95         done
  96         [[ -n $rolist ]] && rolist="ro=${rolist#:}"
  97         [[ -n $rwlist ]] && rwlist="rw=${rwlist#:}"
  98         [[ -n $rootlist ]] && rootlist="root=${rootlist#:}"
  99         for opt in $rolist $rwlist $rootlist; do
 100                 optlist=$optlist,$opt
 101         done
 102         echo ${optlist#,}
 103 }
 104 
 105 # Function to get all sec options from share/mount option string
 106 # Usage: get_sec_str [option_str]
 107 #
 108 function get_sec_str {
 109         typeset Fname=get_sec_str
 110         [[ :$SHAREMNT_DEBUG: == *:$Fname:* \
 111                 || :$SHAREMNT_DEBUG: == *:all:* ]] && set -x
 112         
 113         typeset opts=$1
 114         typeset secopts=""
 115         opts=$(echo $opts | tr "," " ")
 116         for o in $opts; do
 117                 if [[ $o == "sec="* ]]; then
 118                         o=${o#sec=}
 119                         o=$(echo $o | tr ":" " ")
 120                         secopts="$secopts $o"
 121                 fi
 122         done
 123         echo $secopts
 124 }
 125 
 126 # Function to get matched sec option used between client and server.
 127 # Usage: get_sec_opt [mntopt] [shropt]
 128 #
 129 function get_sec_opt {
 130         typeset Fname=get_sec_opt
 131         [[ :$SHAREMNT_DEBUG: == *:$Fname:* \
 132                 || :$SHAREMNT_DEBUG: == *:all:* ]] && set -x
 133 
 134         mntopt=$1
 135         shropt=$2
 136 
 137         typeset sec_opt=""
 138         sec_shr=$(get_sec_str $shropt)
 139         # default sec flavour is "sys" when sharing
 140         [[ -z $sec_shr ]] && sec_shr="sys"
 141         sec_mnt=$(get_sec_str $mntopt)
 142 
 143         if [[ -z $sec_mnt ]]; then
 144                 # if clients doesn't sepcify sec flavour when mounting,
 145                 # use the first one specified when sharing on server
 146                 sec_opt=$(echo $sec_shr | cut -d" " -f1)
 147         else
 148                 if echo $sec_mnt | grep " " >/dev/null; then
 149                         # client can't specify multiple sec flavours when
 150                         # calling mount. Since domount_check() is called
 151                         # only in positive test cases, this shouldn't happen.
 152                         echo "\n$Fname: multiple sec options when mounting"
 153                         echo "*** mntopt=<$mntopt>, shropt=<$shropt>"
 154                         return 1
 155                 fi
 156 
 157                 # look for if $sec_shr contains the one specified by
 158                 # client
 159                 for o in $sec_shr; do
 160                         [[ $o == $sec_mnt ]] && sec_opt=$o && break
 161                 done
 162         fi
 163 
 164         if [[ -z $sec_opt ]]; then
 165                 # couldn't find matched sec option. This shouldn't happen
 166                 # because domount_check() is called only in positive test
 167                 echo "\n$Fname: didn't find matched sec flavor"
 168                 echo "*** mntopt=<$mntopt>, shropt=<$shropt>"
 169                 return 1
 170         fi
 171 
 172         echo "sec=$sec_opt"
 173 }
 174 
 175 # Function to do an NFS share with option provided at SERVER;
 176 #   then verify filesystem is shared correctly with the option
 177 #   SERVER, SHRDIR, MNTDIR and STF_TMPDIR are global variables
 178 #   Usage: share_check shropt [shared_filesystem]
 179 #
 180 function share_check {
 181         typeset Fname=share_check
 182         [[ :$SHAREMNT_DEBUG: == *:$Fname:* \
 183                 || :$SHAREMNT_DEBUG: == *:all:* ]] && set -x
 184 
 185         typeset shropt=${1}     # options to use in share and check
 186         [[ -n ${2} ]] && typeset SHRDIR=${2}
 187 
 188         # provide the new share options to server
 189         # and reshare SHRDIR with these options
 190         echo "$shropt" > $STF_TMPDIR/shropt.out.$$
 191 
 192         scp $STF_TMPDIR/shropt.out.$$ \
 193                 root@$SERVER:$SRV_TMPDIR/ShrOpts.sharemnt \
 194                 > $STF_TMPDIR/rcp.out.$$ 2>&1
 195         if [[ $? != 0 ]]; then
 196                 echo "$Fname: failed to copy <shropt.out.$$> to <$SERVER>"
 197                 cat $STF_TMPDIR/rcp.out.$$
 198                 cleanup $STF_UNRESOLVED
 199         fi
 200 
 201         echo "Resharing $SHRDIR with <$shropt> options ... \c"
 202         typeset SRVDEBUG=$STC_GENUTILS_DEBUG:$SHAREMNT_DEBUG
 203         [[ :$SRVDEBUG: == *:RSH:* ]] && SRVDEBUG=all
 204         RSH root $SERVER \
 205                 "export SHAREMNT_DEBUG=$SRVDEBUG; \
 206                 $SRV_TMPDIR/srv_setup -r $SHRDIR" \
 207                 > $STF_TMPDIR/rsh.out.$$ 2>&1
 208         rc=$?
 209         [[ :$SRVDEBUG: == *:all:* ]] && cat $STF_TMPDIR/rsh.out.$$ 1>&2
 210         grep "Done" $STF_TMPDIR/rsh.out.$$ > /dev/null 2>&1
 211         if [[ $? != 0 || $rc != 0 ]]; then
 212                 echo "$Fname: run $SRV_TMPDIR/srv_setup in $SERVER failed"
 213                 cat $STF_TMPDIR/rsh.out.$$
 214                 cleanup $STF_FAIL
 215         fi
 216 
 217         echo "OK"
 218         rm -f $STF_TMPDIR/*.out.$$
 219 }
 220 
 221 # Function to do an NFS mount;
 222 #   then verify filesystem is mounted correctly with provided option
 223 #   SERVER, SHRDIR, MNTDIR and STF_TMPDIR are global variables
 224 #   Usage: domount_check [URL] mntopt [shropt] [shared_filesystem]
 225 #
 226 function domount_check {
 227         typeset Fname=domount_check
 228         [[ :$SHAREMNT_DEBUG: == *:$Fname:* \
 229                 || :$SHAREMNT_DEBUG: == *:all:* ]] && set -x
 230 
 231         typeset -i isURL=0
 232         if [[ $1 == URL ]]; then
 233                 isURL=1
 234                 shift
 235         fi
 236         typeset mntopt=${1}     # options to use in mount and check
 237         typeset shropt=${2}     # options to use in share and check
 238         typeset opt_flg
 239         [[ -n ${3} ]] && typeset SHRDIR=${3}
 240         [[ -n $mntopt ]] && opt_flg="-o"
 241 
 242         echo $mntopt | grep -i remount > /dev/null 2>&1
 243         if (( $? != 0 )); then
 244                 # make sure MNTDIR is not mounted at this point
 245                 umount -f $MNTDIR > /dev/null 2>&1
 246         fi
 247 
 248         typeset resource="$SERVER:${SHRDIR}${SHRDIR_OFFSET}"
 249         (( isURL == 1 )) && resource="nfs://$SERVER${SHRDIR}${SHRDIR_OFFSET}"
 250         echo "Mounting $resource at $MNTDIR with MNTOPT=<$mntopt> ... \c"
 251         mount -F nfs $opt_flg $mntopt $resource $MNTDIR \
 252                 > $STF_TMPDIR/mnt.out.$$ 2>&1
 253         if (( $? != 0 )); then
 254                 echo "\n$Fname: mount failed"
 255                 cat $STF_TMPDIR/mnt.out.$$
 256                 cleanup $STF_FAIL
 257         fi
 258         echo "OK"
 259 
 260         echo "Checking $MNTDIR with MNTOPT=$mntopt ... \c"
 261         nfsstat -m $MNTDIR > $STF_TMPDIR/nstat.out.$$ 2>&1
 262         if (( $? != 0 )); then
 263                 echo "\n$Fname: nfsstat failed"
 264                 cat $STF_TMPDIR/nstat.out.$$
 265                 cleanup $STF_UNRESOLVED
 266         fi
 267         mount | grep "^$MNTDIR on" > $STF_TMPDIR/opt.out.$$
 268 
 269         typeset sec_opt=""
 270         if [[ -n $shropt ]]; then
 271             sec_opt=$(get_sec_opt "$mntopt" $shropt) || cleanup $STF_UNRESOLVED
 272         fi
 273 
 274         typeset OPTs=$(echo $mntopt | sed 's/,/ /g')
 275         if ! echo $OPTs || grep "sec=" >/dev/null; then
 276                 OPTs="$OPTs $sec_opt"
 277         fi
 278         for opt in $OPTs; do
 279                 case $opt in
 280                 rw|remount) grep -w "read" $STF_TMPDIR/opt.out.$$ | \
 281                                 grep -w "write" > /dev/null 2>&1
 282                         rc=$?
 283                         ;;
 284                 ro) grep "read only" $STF_TMPDIR/opt.out.$$ > /dev/null 2>&1
 285                         rc=$?
 286                         ;;
 287                 sec=krb5*) grep "Flags:" $STF_TMPDIR/nstat.out.$$ | \
 288                                 grep "$opt," > /dev/null 2>&1
 289                         rc=$?
 290                         ;;
 291                 *) grep "Flags:" $STF_TMPDIR/nstat.out.$$ | \
 292                                 grep -w "$opt" > /dev/null 2>&1
 293                         rc=$?
 294                         if (( $rc != 0 )); then
 295                                 grep -w "$opt" $STF_TMPDIR/opt.out.$$ \
 296                                         > /dev/null 2>&1
 297                                 rc=$?
 298                         fi
 299                         ;;
 300                 esac
 301                 if (( $rc != 0 )); then
 302                         echo "\n$Fname: didn't get correct <$opt> \c"
 303                         echo "in mntopt<$mntopt>"
 304                         echo "*** opt=<$opt>, shropt=<$shropt>"
 305                         cat $STF_TMPDIR/opt.out.$$
 306                         cat $STF_TMPDIR/nstat.out.$$
 307                         cleanup $STF_FAIL
 308                 fi
 309         done
 310 
 311         echo "OK"
 312         rm -f $STF_TMPDIR/*.out.$$
 313 }
 314 
 315 # Function to unmount an NFS mount point;
 316 #   then verify filesystem is unmounted successfully
 317 #   SERVER, SHRDIR, MNTDIR and STF_TMPDIR are global variables
 318 #   Usage: unmount_check
 319 #
 320 function unmount_check {
 321         typeset Fname=unmount_check
 322         [[ :$SHAREMNT_DEBUG: == *:$Fname:* \
 323                 || :$SHAREMNT_DEBUG: == *:all:* ]] && set -x
 324 
 325         echo "Unmounting current mount point $MNTDIR ... \c"
 326 
 327         wait_now 10 "umount $MNTDIR > $STF_TMPDIR/umnt.out.$$ 2>&1"
 328         if [[ $? != 0 ]]; then
 329                 echo "\n$Fname: umount failed"
 330                 cat $STF_TMPDIR/umnt.out.$$
 331                 cleanup $STF_FAIL
 332         fi
 333         nfsstat -m $MNTDIR | grep "$MNTDIR" > /dev/null 2>&1
 334         if [[ $? == 0 ]]; then
 335                 echo "\n$Fname: umount didn't unmount $MNTDIR successfully"
 336                 echo "... $MNTDIR is still mounted"
 337                 nfsstat -m $MNTDIR
 338                 cleanup $STF_FAIL
 339         fi
 340 
 341         echo "OK"
 342         rm -f $STF_TMPDIR/*.out.$$
 343 }
 344 
 345 # Function to do an NFS automount;
 346 #   then verify filesystem is mounted correctly with provided option
 347 #   SERVER, SHRDIR, MNTDIR and STF_TMPDIR are global variables
 348 #   Usage: automount_check [URL] mntopt [shropt] [tag] [shared_filesystem]
 349 #
 350 function automount_check {
 351         typeset Fname=automount_check
 352         [[ :$SHAREMNT_DEBUG: == *:$Fname:* \
 353                 || :$SHAREMNT_DEBUG: == *:all:* ]] && set -x
 354 
 355         typeset -i isURL=0
 356         if [[ $1 == URL ]]; then
 357                 isURL=1
 358                 shift
 359         fi
 360         typeset mntopt=${1}     # options to use in mount and check
 361         typeset shropt=${2}     # options to use in share and check
 362         typeset tn="${3}_$$_"   # short unique name for auto entry name
 363         [[ -n ${4} ]] && typeset SHRDIR=${4}
 364 
 365         # Insert the entry of these options to the map
 366         typeset resource="$SERVER:${SHRDIR}${SHRDIR_OFFSET}"
 367         (( isURL == 1 )) && resource="nfs://$SERVER${SHRDIR}${SHRDIR_OFFSET}"
 368         an=$(echo "$mntopt" | sed -e 's/sec=//g' -e 's/://g')
 369         an="$tn$an"
 370         echo "SM_$an -${mntopt} $resource" \
 371                 > $STF_TMPDIR/auto_indirect.shmnt
 372 
 373         echo "Auto-Mounting (indirectly) $AUTOIND/SM_$an ..."
 374         echo "\t with MNTOPT=<$mntopt> ... \c"
 375         # If resource is a file, use "ls" instead of "cd" to mount
 376         ckFILE=$(basename $SHRDIR)
 377         if [[ $ckFILE == *file ]]; then
 378                 # first time automount tries to check for ISDIR, ignore
 379                 ckCMD="ls -lv"
 380                 $ckCMD $AUTOIND/SM_$an > /dev/null 2>&1
 381         else
 382                 ckCMD="cd"
 383         fi
 384         $ckCMD $AUTOIND/SM_$an > $STF_TMPDIR/amnt.out.$$ 2>&1
 385         if (( $? != 0 )); then
 386                 echo "\n$Fname: automount ($ckCMD $AUTOIND/SM_$an) failed"
 387                 cat $STF_TMPDIR/amnt.out.$$
 388                 nfsstat -m $AUTOIND/SM_$an
 389                 cleanup $STF_FAIL
 390         fi
 391         echo "OK"
 392 
 393         echo "Checking $AUTOIND/SM_$an with MNTOPT=$mntopt ... \c"
 394         nfsstat -m $AUTOIND/SM_$an > $STF_TMPDIR/nstat.out.$$ 2>&1
 395         if (( $? != 0 )); then
 396                 echo "\n$Fname: nfsstat failed"
 397                 cat $STF_TMPDIR/nstat.out.$$
 398                 cleanup $STF_UNRESOLVED
 399         fi
 400         mount | grep "$AUTOIND/SM_$an" > $STF_TMPDIR/opt.out.$$
 401 
 402         typeset sec_opt=""
 403         if [[ -n $shropt ]]; then
 404             sec_opt=$(get_sec_opt "$mntopt" $shropt) || cleanup $STF_UNRESOLVED
 405         fi
 406 
 407         typeset OPTs=$(echo $mntopt | sed 's/,/ /g')
 408         if ! echo $OPTs || grep "sec=" >/dev/null; then
 409                 OPTs="$OPTs $sec_opt"
 410         fi
 411         for opt in $OPTs; do
 412                 case $opt in
 413                 rw) grep -w "read" $STF_TMPDIR/opt.out.$$ | \
 414                                 grep -w "write" > /dev/null 2>&1
 415                         rc=$?
 416                         ;;
 417                 ro) grep "read only" $STF_TMPDIR/opt.out.$$ > /dev/null 2>&1
 418                         rc=$?
 419                         ;;
 420                 sec=krb5*) grep "Flags:" $STF_TMPDIR/nstat.out.$$ | \
 421                                 grep "$opt," > /dev/null 2>&1
 422                         rc=$?
 423                         ;;
 424                 *) grep "Flags:" $STF_TMPDIR/nstat.out.$$ | \
 425                                 grep -w "$opt" > /dev/null 2>&1
 426                         rc=$?
 427                         if (( $rc != 0 )); then
 428                                 grep -w "$opt" $STF_TMPDIR/opt.out.$$ \
 429                                         > /dev/null 2>&1
 430                                 rc=$?
 431                         fi
 432                         ;;
 433                 esac
 434                 if (( $rc != 0 )); then
 435                         echo "\n$Fname: didn't get correct <$opt> \c"
 436                         echo "in mntopt<$mntopt>"
 437                         echo "*** opt=<$opt>, shropt=<$shropt>"
 438                         cat $STF_TMPDIR/opt.out.$$
 439                         cat $STF_TMPDIR/nstat.out.$$
 440                         cleanup $STF_FAIL
 441                 fi
 442         done
 443 
 444         echo "OK"
 445         rm -f $STF_TMPDIR/*.out.$$
 446 }
 447 
 448 # Function to check the unknown users map
 449 #   Usage: do_anon_check <anon_uid> <file>
 450 #
 451 function do_anon_check {
 452         typeset Fname=do_anon_check
 453         [[ :$SHAREMNT_DEBUG: == *:$Fname:* \
 454                 || :$SHAREMNT_DEBUG: == *:all:* ]] && set -x
 455 
 456         typeset anon_uid=$1
 457         typeset real_uid=$(ls -ln $2 | awk '{print $3}')
 458         if [[ $real_uid == $anon_uid ]]; then
 459                 return 0
 460         else
 461                 echo "\tthe file owner is $real_uid instead of $anon_uid"
 462                 return 1
 463         fi
 464 }
 465 
 466 # Function to do read/write testing in the NFS mount point
 467 #   SERVER, SHRDIR, MNTDIR and STF_TMPDIR are global variables
 468 #   Usage: do_rw_test [test_file_name]
 469 #               test_file_name - the name of log file. If this
 470 #               isn't specified, a default name will be used.
 471 #
 472 #          do_rw_test <directive> <args>
 473 #          1. directive = OWNER
 474 #             args - the expected owner of the file created
 475 #                       in the test.
 476 #          2. directive = ANON
 477 #             args - share options
 478 #          3. directive = WRITER
 479 #             args - user name
 480 #
 481 function do_rw_test {
 482         typeset Fname=do_rw_test
 483         [[ :$SHAREMNT_DEBUG: == *:$Fname:* \
 484                 || :$SHAREMNT_DEBUG: == *:all:* ]] && set -x
 485 
 486         typeset Tfile=tfile.$$
 487         typeset expected_owner=""
 488         typeset anon_uid=""
 489         typeset write_user=""
 490         if (( $# == 1 )); then
 491                 Tfile=${1}
 492         elif (( $# > 1 )); then
 493                 case $1 in
 494                 ANON)
 495                         if [[ -n $2 && $2 == *anon=* ]]; then
 496                             anon_uid=$(echo $2 | sed -e 's/.*anon=//;s/,.*//')
 497                         else
 498                             anon_uid=$(id nobody | \
 499                                 sed 's/uid=\(.*\)(nobody) gid=.*/\1/')
 500                         fi
 501                 ;;
 502                 OWNER)
 503                         expected_owner=$2
 504                 ;;
 505                 WRITER)
 506                         write_user=$2
 507                         expected_owner=$2
 508                 ;;
 509                 *) echo "\n$Fname: Unknown keyword"
 510                 exit $STF_UNRESOLVED
 511                 ;;
 512                 esac
 513         fi
 514 
 515         echo "Doing READ/WRITE testing at $MNTDIR ... \c"
 516         typeset TData="READ/WRITE tests at $MNTDIR"
 517 
 518         if [[ -n $write_user ]]; then
 519                 su $write_user -c "echo $TData > $MNTDIR/$Tfile" \
 520                         2> $STF_TMPDIR/wr.out.$$
 521         else
 522                 echo "$TData" 1> $MNTDIR/$Tfile 2> $STF_TMPDIR/wr.out.$$
 523         fi
 524         if (( $? != 0 )); then
 525                 echo "\n$Fname: WRITE to $MNTDIR failed"
 526                 cat $STF_TMPDIR/wr.out.$$
 527                 cleanup $STF_FAIL
 528         fi
 529         if [[ -n $anon_uid ]]; then
 530                 do_anon_check $anon_uid $MNTDIR/$Tfile \
 531                         > $STF_TMPDIR/anon.out.$$ 2>&1
 532                 if (( $? != 0 )); then
 533                         echo "\n$Fname: the file owner is not expected"
 534                         cat $STF_TMPDIR/anon.out.$$
 535                         cleanup $STF_FAIL
 536                 fi
 537         fi
 538         if [[ -n $write_user ]]; then
 539             su $write_user -c "ls -lv $MNTDIR/$Tfile" \
 540                 2> $STF_TMPDIR/ls.out.$$ | grep "$Tfile" > /dev/null 2>&1
 541         else
 542             ls -lv $MNTDIR/$Tfile 2> $STF_TMPDIR/ls.out.$$ | \
 543                 grep "$Tfile" > /dev/null 2>&1
 544         fi
 545         if (( $? != 0 )); then
 546                 echo "\n$Fname: READDIR of <$Tfile> in $MNTDIR failed"
 547                 cat $STF_TMPDIR/ls.out.$$
 548                 cleanup $STF_FAIL
 549         fi
 550         if [[ -n $expected_owner ]]; then
 551                 if [[ -n $write_user ]]; then
 552                     typeset ck_line=$(su $write_user -c "ls -l $MNTDIR/$Tfile")
 553                 else
 554                     typeset ck_line=$(ls -l $MNTDIR/$Tfile)
 555                 fi
 556                 echo $ck_line | awk '{print $3}' | grep -w $expected_owner \
 557                         > /dev/null 2>&1
 558                 if (( $? != 0 )); then
 559                         echo "\n$Fname: <$Tfile> has incorrected owner"
 560                         echo $ck_line
 561                         cleanup $STF_FAIL
 562                 fi
 563         fi
 564         if [[ -n $write_user ]]; then
 565                 typeset fdata=$(su $write_user -c "cat $MNTDIR/$Tfile" \
 566                                         2> $STF_TMPDIR/cat.out.$$)
 567         else
 568                 typeset fdata=$(cat $MNTDIR/$Tfile 2> $STF_TMPDIR/cat.out.$$)
 569         fi
 570         if [[ "$fdata" != "$TData" ]]; then
 571                 echo "\n$Fname: READ file in $MNTDIR failed"
 572                 cat $STF_TMPDIR/cat.out.$$
 573                 cleanup $STF_FAIL
 574         fi
 575         if [[ -n $write_user ]]; then
 576                 su $write_user -c "rm $MNTDIR/$Tfile" 2> $STF_TMPDIR/rm.out.$$
 577         else
 578                 rm $MNTDIR/$Tfile 2> $STF_TMPDIR/rm.out.$$
 579         fi
 580         if (( $? != 0 )); then
 581                 echo "\n$Fname: Remove $MNTDIR/$Tfile failed"
 582                 cat $STF_TMPDIR/rm.out.$$
 583                 cleanup $STF_FAIL
 584         fi
 585 
 586         echo "OK"
 587         rm -f $STF_TMPDIR/*.out.$$
 588 }
 589 
 590 # Function to do read only testing in the NFS mount point
 591 #   SERVER, SHRDIR, MNTDIR and STF_TMPDIR are global variables
 592 #   Usage: do_ro_test
 593 #
 594 function do_ro_test {
 595         typeset Fname=do_ro_test
 596         [[ :$SHAREMNT_DEBUG: == *:$Fname:* \
 597                 || :$SHAREMNT_DEBUG: == *:all:* ]] && set -x
 598 
 599         echo "Doing READ ONLY testing at $MNTDIR ... \c"
 600         typeset TData="This is a rofile for sharemnt Testing"
 601         ls -lv $MNTDIR/rofile 2> $STF_TMPDIR/ls.out.$$ | \
 602                 grep "rofile" > /dev/null 2>&1
 603         if [[ $? != 0 ]]; then
 604                 echo "\n$Fname: READDIR of <rofile> in $MNTDIR failed"
 605                 cat $STF_TMPDIR/ls.out.$$
 606                 cleanup $STF_FAIL
 607         fi
 608         typeset fdata=$(head -1 $MNTDIR/rofile 2> $STF_TMPDIR/head.out.$$)
 609         if [[ "$fdata" != "$TData" ]]; then
 610                 echo "\n$Fname: READ rofile in $MNTDIR failed"
 611                 cat $STF_TMPDIR/head.out.$$
 612                 cleanup $STF_FAIL
 613         fi
 614         echo "New Line" >> $MNTDIR/rofile 2> /dev/null
 615         if [[ $? == 0 ]]; then
 616                 echo "\n$Fname: Unexpected successful to write into rofile"
 617                 cat $MNTDIR/rofile
 618                 cleanup $STF_FAIL
 619         fi
 620 
 621         echo "OK"
 622         rm -f $STF_TMPDIR/*.out.$$
 623 }
 624 
 625 # Function to do negative read testing in the NFS mount point
 626 #   SERVER, SHRDIR, MNTDIR and STF_TMPDIR are global variables
 627 #   Usage: do_neg_ro_test
 628 #
 629 function do_neg_ro_test {
 630         typeset Fname=do_neg_ro_test
 631         [[ :$SHAREMNT_DEBUG: == *:$Fname:* \
 632                 || :$SHAREMNT_DEBUG: == *:all:* ]] && set -x
 633 
 634         echo "Doing NEGATIVE READ testing at $MNTDIR ... \c"
 635         ls -lv $MNTDIR >$STF_TMPDIR/*.out.$$ 2>&1
 636         if [[ $? == 0 ]]; then
 637                 echo "\n$Fname: READDIR in $MNTDIR succeeded, but it shouldn't"
 638                 cat $STF_TMPDIR/*.out.$$
 639                 cleanup $STF_FAIL
 640         fi
 641 
 642         echo "OK"
 643         rm -f $STF_TMPDIR/*.out.$$
 644 }
 645 
 646 # Function to do an NFS share;
 647 #   then verify filesystem can not be shared with provided options
 648 #   Usage: do_neg_share_check shropt [shared_filesystem]
 649 #
 650 function do_neg_share_check {
 651         typeset Fname=do_neg_share_check
 652         [[ :$SHAREMNT_DEBUG: == *:$Fname:* \
 653                 || :$SHAREMNT_DEBUG: == *:all:* ]] && set -x
 654         typeset shropt=${1}     # options to use in share
 655         [[ -n ${2} ]] && typeset SHRDIR=${2}
 656 
 657         # provide the new share options to server
 658         # and reshare SHRDIR with these options
 659         echo "$shropt" > $STF_TMPDIR/shropt.out.$$
 660 
 661         scp $stf_tmpdir/Shropt.out.$$ \
 662                 root@$SERVER:$SRV_TMPDIR/ShrOpts.sharemnt \
 663                 > $STF_TMPDIR/rcp.out.$$ 2>&1
 664         if [[ $? != 0 ]]; then
 665                 echo "$Fname: failed to copy <shropt.out.$$> to <$SERVER>"
 666                 cat $STF_TMPDIR/rcp.out.$$
 667                 cleanup $STF_UNRESOLVED
 668         fi
 669 
 670         echo "Resharing $SHRDIR with <$shropt> options ... \c"
 671         typeset SRVDEBUG=$STC_GENUTILS_DEBUG:$SHAREMNT_DEBUG
 672         [[ :$SRVDEBUG: == *:RSH:* ]] && SRVDEBUG=all
 673         RSH root $SERVER \
 674                 "export SHAREMNT_DEBUG=$SRVDEBUG; \
 675                 $SRV_TMPDIR/srv_setup -r $SHRDIR" \
 676                 > $STF_TMPDIR/rsh.out.$$ 2>&1
 677         [[ :$SRVDEBUG: == *:all:* ]] && cat $STF_TMPDIR/rsh.out.$$ 1>&2
 678         grep "Done" $STF_TMPDIR/rsh.out.$$ > /dev/null 2>&1
 679         if [[ $? == 0 ]]; then
 680                 echo "\n$Fname: run $SRV_TMPDIR/srv_setup in $SERVER succeeded"
 681                 echo "$Fname: share succeeded, but it should fail for"
 682                 echo "\t the invalid SHROPT=<$shropt>"
 683                 cat $STF_TMPDIR/rsh.out.$$
 684                 cleanup $STF_FAIL
 685         fi
 686 
 687         echo "OK"
 688         rm -f $STF_TMPDIR/*.out.$$
 689 }
 690 
 691 # Function to do an NFS mount;
 692 #   then verify filesystem can not be mounted with provided options
 693 #   Usage: do_neg_mount_check mntopt
 694 #
 695 function do_neg_mount_check {
 696         typeset Fname=do_neg_mount_check
 697         [[ :$SHAREMNT_DEBUG: == *:$Fname:* \
 698                 || :$SHAREMNT_DEBUG: == *:all:* ]] && set -x
 699         typeset mntopt=${1}     # options to use in mount
 700         typeset opts=""
 701         [[ -n $mntopt ]] && opts="-o $mntopt"
 702 
 703         echo $mntopt | grep -i remount > /dev/null 2>&1
 704         if (( $? != 0 )); then
 705                 # make sure MNTDIR is not mounted at this point
 706                 umount -f $MNTDIR > /dev/null 2>&1
 707         fi
 708 
 709         echo "Mounting $SERVER:${SHRDIR}${SHRDIR_OFFSET} at $MNTDIR"
 710         echo "\t with MNTOPT=<$mntopt> ... \c"
 711         mount -F nfs $opts "$SERVER":${SHRDIR}${SHRDIR_OFFSET} $MNTDIR \
 712                 > $STF_TMPDIR/mnt.out.$$ 2>&1
 713         if [[ $? == 0 && ,$mntopt, == @(*,vers=2,*|*,vers=3,*) ]]; then
 714                 echo "\n$Fname: mount succeeded, but it should fail"
 715                 cat $STF_TMPDIR/mnt.out.$$
 716                 umount -f $MNTDIR > /dev/null 2>&1
 717                 cleanup $STF_FAIL
 718         fi
 719         echo "OK"
 720         echo $mntopt | grep -i remount > /dev/null 2>&1
 721         if (( $? == 0 )); then
 722                 rm -f $STF_TMPDIR/*.out.$$
 723                 return
 724         fi
 725 
 726         echo "Checking $MNTDIR with MNTOPT=$mntopt ... \c"
 727         nfsstat -m $MNTDIR > $STF_TMPDIR/nstat.out.$$ 2>&1
 728         if (( $? != 0 )); then
 729                 echo "\n$Fname: nfsstat failed"
 730                 cat $STF_TMPDIR/nstat.out.$$
 731                 cleanup $STF_UNRESOLVED
 732         elif [[ -s $STF_TMPDIR/nstat.out.$$ && \
 733             ,$mntopt, == @(*,vers=2,*|*,vers=3,*) ]]; then
 734                 echo "\n$Fname: it is wrong for nfsstat to display some info."
 735                 cat $STF_TMPDIR/nstat.out.$$
 736                 umount -f $MNTDIR > /dev/null 2>&1
 737                 cleanup $STF_FAIL
 738         fi
 739 
 740         mount | grep "^$MNTDIR on" > $STF_TMPDIR/opt.out.$$
 741         if [[ $? == 0 && ,$mntopt, == @(*,vers=2,*|*,vers=3,*) ]]; then
 742                 echo "\n$Fname: it is wrong to be found via mount."
 743                 cat $STF_TMPDIR/opt.out.$$
 744                 umount -f $MNTDIR > /dev/null 2>&1
 745                 cleanup $STF_FAIL
 746         fi
 747 
 748         ls -l $MNTDIR/rofile > $STF_TMPDIR/ls.out.$$ 2>/dev/null
 749         if [[ $? == 0 && ,$mntopt, != @(*,vers=2,*|*,vers=3,*) ]]; then
 750                 echo "\n$Fname: it is wrong to find rofile:"
 751                 cat $STF_TMPDIR/ls.out.$$
 752                 umount -f $MNTDIR > /dev/null 2>&1
 753                 cleanup $STF_FAIL
 754         fi
 755 
 756         rm -f $STF_TMPDIR/*.out.$$
 757         echo "OK"
 758 }
 759 
 760 # Function to do an NFS automount;
 761 #   then verify filesystem can not be mounted with provided options
 762 #   Usage: do_neg_automount_check mntopt [tag]
 763 #
 764 function do_neg_automount_check {
 765         typeset Fname=do_neg_automount_check
 766         [[ :$SHAREMNT_DEBUG: == *:$Fname:* \
 767                 || :$SHAREMNT_DEBUG: == *:all:* ]] && set -x
 768         typeset mntopt=${1}     # options to use in mount
 769         typeset tn="${2}_$$_"   # short unique name for auto entry name
 770 
 771         # Insert the entry of these options to the map
 772         an=$(echo "$mntopt" | sed -e 's/sec=//g' -e 's/://g')
 773         an="$tn$an"
 774         echo  "SM_$an -${mntopt} ${SERVER}:${SHRDIR}${SHRDIR_OFFSET}" \
 775                 > $STF_TMPDIR/auto_indirect.shmnt
 776 
 777         echo "Auto-Mounting (indirectly) $AUTOIND/SM_$an ..."
 778         echo "\t with MNTOPT=<$mntopt> ..."
 779         cd "$AUTOIND/SM_$an" > $STF_TMPDIR/amnt.out.$$ 2>&1
 780         if [[ $? == 0 && ,$mntopt, == @(*,vers=2,*|*,vers=3,*) ]]; then
 781                 echo "$Fname: automount (cd $AUTOIND/SM_$an) succeeded, \c"
 782                 echo "but it should fail"
 783                 cat $STF_TMPDIR/amnt.out.$$
 784                 umount -f $AUTOIND/SM_$an > /dev/null 2>&1
 785                 cleanup $STF_FAIL
 786         fi
 787 
 788         echo "Checking $AUTOIND/SM_$an with MNTOPT=$mntopt ..."
 789         nfsstat -m "$AUTOIND/SM_$an" > $STF_TMPDIR/nstat.out.$$ 2>&1
 790         if (( $? != 0 )); then
 791                 echo "\n$Fname: nfsstat failed"
 792                 cat $STF_TMPDIR/nstat.out.$$
 793                 cleanup $STF_UNRESOLVED
 794         elif [[ -s $STF_TMPDIR/nstat.out.$$ && \
 795             ,$mntopt, == @(*,vers=2,*|*,vers=3,*) ]]; then
 796                 echo "\n$Fname: it is wrong for nfsstat to display some info."
 797                 cat $STF_TMPDIR/nstat.out.$$
 798                 umount -f $AUTOIND/SM_$an > /dev/null 2>&1
 799                 cleanup $STF_FAIL
 800         fi
 801 
 802         mount | grep "^$AUTOIND/SM_$an on" > $STF_TMPDIR/opt.out.$$
 803         if [[ $? == 0 && ,$mntopt, == @(*,vers=2,*|*,vers=3,*) ]]; then
 804                 echo "\n$Fname: it is wrong to be found via mount."
 805                 cat $STF_TMPDIR/opt.out.$$
 806                 umount -f $AUTOIND/SM_$an > /dev/null 2>&1
 807                 cleanup $STF_FAIL
 808         fi
 809 
 810         ls -l $AUTOIND/SM_$an/rofile > $STF_TMPDIR/ls.out.$$ 2>/dev/null
 811         if [[ $? == 0 && ,$mntopt, != @(*,vers=2,*|*,vers=3,*) ]]; then
 812                 echo "\n$Fname: it is wrong to find rofile:"
 813                 cat $STF_TMPDIR/ls.out.$$
 814                 umount -f $AUTOIND/SM_$an > /dev/null 2>&1
 815                 cleanup $STF_FAIL
 816         fi
 817 
 818         rm -f $STF_TMPDIR/*.out.$$
 819         echo "OK"
 820 }
 821 
 822 # Function to modify default_tgs_enctypes and default_tkt_enctypes
 823 #   in krb5.conf and create nfs principal with specified enctype.
 824 #   Usage: setup_enctype enctype_for_cfgfile enctype_for_nfs
 825 #
 826 function setup_enctype {
 827         typeset Fname=setup_enctype
 828         [[ :$SHAREMNT_DEBUG: == *:$Fname:* \
 829                 || :$SHAREMNT_DEBUG: == *:all:* ]] && set -x
 830         typeset logfile=$STF_TMPDIR/$Fname.$$
 831 
 832         if (( $# < 2 )); then
 833                 echo "Usage: setup_enctype enctype_in_cfgfile enctype_of_nfssrv"
 834                 exit $STF_UNINITIATED
 835         fi
 836 
 837         typeset enctype_in_cfgfile=$1
 838         typeset enctype_of_nfssrv=$2
 839 
 840         # remove existing entries in krb5.conf if there are any
 841         egrep -v "default_tgs_enctypes|default_tkt_enctypes" \
 842             /etc/krb5/krb5.conf > /etc/krb5/krb5.tmp
 843 
 844         # add user specified enctype values in krb5.conf
 845         if [[ $enctype_in_cfgfile != "DEFAULT" ]]; then
 846                 awk '/^\[libdefaults\]$/ {
 847                         print $0;
 848                         printf "\tdefault_tgs_enctypes=%s\n",enc;
 849                         printf "\tdefault_tkt_enctypes=%s\n",enc;
 850                         continue } {print $0}' \
 851                     enc=$enctype_in_cfgfile /etc/krb5/krb5.tmp \
 852                     > /etc/krb5/krb5.conf
 853         else
 854                 mv /etc/krb5/krb5.tmp /etc/krb5/krb5.conf
 855         fi
 856 
 857         # remove nfs principal on the server
 858         princadm -c -p nfs/$SRV_FQDN $SRV_FQDN. 2>$logfile
 859         ckresult $? "princadm failed" $logfile || exit $STF_UNINITIATED
 860 
 861         # create nfs principal using user specified enctypes
 862         typeset enctype_opt=""
 863         [[ $enctype_of_nfssrv != DEFAULT ]] \
 864             && enctype_opt=",enctype=$enctype_of_nfssrv"
 865         princadm -s -p nfs/$SRV_FQDN"$enctype_opt" $SRV_FQDN. 2>$logfile
 866         ckresult $? "princadm failed" $logfile || exit $STF_UNINITIATED
 867 }
 868 
 869 # Function to restore changes made by setup_enctype(). It removes
 870 #   default_tgs_enctypes and default_tkt_enctypes from krb5.conf and
 871 #   create nfs principals with default enctypes.
 872 #
 873 function cleanup_enctype {
 874         setup_enctype DEFAULT DEFAULT
 875 }
 876 
 877 # Function to rcp the dfstab file to SERVER if provided and
 878 #   run shareall to share all entries in /etc/dfs/dfstab and
 879 #   verify all entries are shared with needed options
 880 #   Usage: do_shareall_check dfstab_file
 881 #
 882 function do_shareall_check {
 883         typeset Fname=do_shareall_check
 884         [[ :$SHAREMNT_DEBUG: == *:$Fname:* \
 885                 || :$SHAREMNT_DEBUG: == *:all:* ]] && set -x
 886 
 887         typeset shrfile=$1
 888 
 889         # provide the new dfstab file to server
 890         # and make those share entries effective by shareall
 891         scp $shrfile root@$SERVER:/etc/dfs/dfstab \
 892                 > $STF_TMPDIR/rcp.out.$$ 2>&1
 893         if (( $? != 0 )); then
 894                 echo "$Fname: failed to copy <$shrfile> to <$SERVER>"
 895                 cat $STF_TMPDIR/rcp.out.$$
 896                 cleanup $STF_UNRESOLVED
 897         fi
 898 
 899         echo "Sharing all entries in $SERVER:/etc/dfs/dfstab ... \c"
 900         typeset SRVDEBUG=$STC_GENUTILS_DEBUG:$SHAREMNT_DEBUG
 901         [[ :$SRVDEBUG: == *:RSH:* ]] && SRVDEBUG=all
 902         RSH root $SERVER \
 903                 "export SHAREMNT_DEBUG=$SRVDEBUG; \
 904                 $SRV_TMPDIR/sharemnt.others -S" \
 905                 > $STF_TMPDIR/rsh.out.$$ 2>&1
 906         rc=$?
 907         [[ :$SRVDEBUG: == *:all:* ]] && cat $STF_TMPDIR/rsh.out.$$ 1>&2
 908         grep "Done" $STF_TMPDIR/rsh.out.$$ > /dev/null 2>&1
 909         if (( $? != 0 || $rc != 0 )); then
 910                 echo "$Fname: run <$SRV_TMPDIR/sharemnt.others -S> \
 911                         in <$SERVER> failed:"
 912                 cat $STF_TMPDIR/rsh.out.$$
 913                 cleanup $STF_FAIL
 914         fi
 915 
 916         echo "OK"
 917         rm -f $STF_TMPDIR/*.out.$$
 918 }
 919 
 920 # Function to unshare all entries by unshareall in server
 921 #   and delete the dfstab test file in client if provided
 922 #   Usage: do_unshareall_check dfstab_file
 923 #
 924 function do_unshareall_check {
 925         typeset Fname=do_unshareall_check
 926         [[ :$SHAREMNT_DEBUG: == *:$Fname:* \
 927                 || :$SHAREMNT_DEBUG: == *:all:* ]] && set -x
 928 
 929         # delete the given test dfstab file
 930         rm -f $1
 931 
 932         # unshare all test filesystems in server
 933         typeset SRVDEBUG=$STC_GENUTILS_DEBUG:$SHAREMNT_DEBUG
 934         [[ :$SRVDEBUG: == *:RSH:* ]] && SRVDEBUG=all
 935         RSH root $SERVER \
 936                 "export SHAREMNT_DEBUG=$SRVDEBUG; \
 937                 $SRV_TMPDIR/sharemnt.others -U" \
 938                 > $STF_TMPDIR/rsh.out.$$ 2>&1
 939         rc=$?
 940         [[ :$SRVDEBUG: == *:all:* ]] && cat $STF_TMPDIR/rsh.out.$$ 1>&2
 941         grep "Done" $STF_TMPDIR/rsh.out.$$ > /dev/null 2>&1
 942         if (( $? != 0 || $rc != 0 )); then
 943                 echo "$Fname: run <$SRV_TMPDIR/sharemnt.others \c"
 944                 echo "-C in <$SERVER> failed:"
 945                 cat $STF_TMPDIR/rsh.out.$$
 946                 cleanup $STF_FAIL
 947         fi
 948 
 949         echo "OK"
 950         rm -f $STF_TMPDIR/*.out.$$
 951 }
 952 
 953 # Function to get the number of clients configured on server
 954 # Notice:
 955 # stress tests will call this function as it does not support mutilple clients
 956 #
 957 function get_clients_num {
 958         typeset Fname=get_clients_num
 959         [[ :$SHAREMNT_DEBUG: == *:$Fname:* \
 960                 || :$SHAREMNT_DEBUG: == *:all:* ]] && set -x
 961 
 962         RSH root $SERVER \
 963                 "/bin/ls -l $(dirname $SRV_TMPDIR)" \
 964                 > $STF_TMPDIR/rsh.out.$$ 2> $STF_TMPDIR/rsh.err.$$
 965         typeset -i ret=$?
 966 
 967         #
 968         # Once a client is configured on server, we created a tmp dir named
 969         # SRV_TMPDIR which looks like: /var/tmp/TMPDIR_shmnt_client01
 970         # Notice: If SRV_TMPDIR changes, this function should be changed too.
 971         #
 972         typeset name_tag=$(basename $SRV_TMPDIR | awk -F_ '{print $1"_"$2"_"}')
 973         typeset client_num=$(sed '1d' $STF_TMPDIR/rsh.out.$$ | \
 974                 awk '{print $NF}' | egrep "^$name_tag" | wc -l 2>&1)
 975         if (( $ret != 0 )); then
 976                 print -u2 "$Fname: RSH to SERVER<SERVER> failed"
 977                 cat $STF_TMPDIR/rsh.*.$$
 978                 client_num=0
 979         fi
 980         rm -f $STF_TMPDIR/rsh.*.$$
 981 
 982         echo $client_num
 983         return $ret
 984 }
 985 
 986 # Function to delete users via its specific tag
 987 # Usage: del_users <tag>
 988 #
 989 function del_users {
 990         typeset Fname=del_users
 991         [[ :$SHAREMNT_DEBUG: == *:$Fname:* \
 992                 || :$SHAREMNT_DEBUG: == *:all:* ]] && set -x
 993 
 994         typeset ctag=$1
 995         typeset -i ret=0
 996 
 997         grep ":${ctag}:" /etc/passwd > $STF_TMPDIR/$NAME.users.$$ 2>/dev/null
 998         while read line; do
 999                 user=$(echo $line | awk -F: '{print $1}')
1000                 userdel $user
1001                 (( $? != 0 )) && (( ret += 1 ))
1002         done < $STF_TMPDIR/$NAME.users.$$
1003 
1004         rm -f $STF_TMPDIR/$NAME.users.$$
1005         return $ret
1006 }
1007 
1008 # Function to print debug info from a file to stderr
1009 # Usage: print_debug <file>
1010 #
1011 function print_debug {
1012         [[ :$SHAREMNT_DEBUG: == *:$NAME:* \
1013                 || :$SHAREMNT_DEBUG: == *:RSH:* \
1014                 || :$SHAREMNT_DEBUG: == *:all:* ]] && cat $1 1>&2
1015 }