1 #
   2 # Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
   3 # Use is subject to license terms.
   4 #
   5 
   6 #
   7 # This is free software; you can redistribute it and/or modify it
   8 # under the terms of the "Artistic License" which is located in the
   9 # file named "LICENSE.Artistic" which is included with this software.
  10 #
  11 
  12 #
  13 # This file was originally part of the "contrib" portion of the
  14 # TET3 test harness from The OpenGroup, originally found here:
  15 # http://tetworks.opengroup.org/tet/ or ftp://ftp.xopen.org/pub/TET3/
  16 # and later published in hg.opensolaris.org/hg/test-dev/stcnv-gate
  17 #
  18 # A build of that repository delivers this file as part of the
  19 # SUNWstc-tetlite package, which carries the "Artistic" license
  20 # referred to above.
  21 #
  22 
  23 #
  24 # The "Artistic License" places some restrictions on the kinds of
  25 # changes that may be made to this file.  The changes made here
  26 # relative to the original are "portability fixes" to allow these
  27 # functions to operate in the "test-runner" environment.
  28 #
  29 # The original from which this was derived can be found here:
  30 #   https://bitbucket.org/illumos/illumos-stc/
  31 # under the path:
  32 #   usr/src/tools/tet/contrib/ctitools/src/lib/ksh/ctiutils.ksh
  33 
  34 ########################################################################
  35 #
  36 # NAME:         ctiutils.shlib
  37 #
  38 # SYNOPSIS:
  39 #       cti_assert assertion_number assertion_msg
  40 #       cti_report arg ...
  41 #       cti_pass
  42 #       cti_fail [msg ...]
  43 #       cti_unresolved [msg ...]
  44 #       cti_untested [msg ...]
  45 #       cti_unsupported [msg ...]
  46 #       cti_notinuse [msg ...]
  47 #       cti_pathtrace
  48 #       cti_checkpath expected-path-count
  49 #       cti_deleteall reason
  50 #       cti_reportfile path [title]
  51 #       cti_rmf [files...]
  52 #       cti_writefile path mode lines...
  53 #       cti_appendfile path mode lines...
  54 #       cti_execute [-c out|err] [-i input] result cmd [args...]
  55 #       cti_runexpect failtext command pattern action [pattern action ...]
  56 #       cti_expecttest failtext command pattern action [pattern action ...]
  57 #       cti_cancel test_num [msg ...] [test result]
  58 #       cti_cancelall [msg ...] [test result]
  59 #
  60 # DESCRIPTION:
  61 #       Common korn shell functions for tests.
  62 #
  63 #       cti_report() writes an informational line to the journal.
  64 #
  65 #       The functions cti_pass(), cti_fail(), cti_unresolved(),
  66 #       cti_untested(), cti_unsupported() and cti_notinuse() each
  67 #       registers the corresponding result code against the current test,
  68 #       and write any arguments to the execution results file, as a
  69 #       single line.
  70 #
  71 #       The cti_pathtrace() and cti_checkpath() are used in path tracing.
  72 #       cti_pathtrace() increments the variable pathok. cti_checkpath()
  73 #       checks the path tracing and registers a PASS result if
  74 #       appropriate.
  75 #
  76 #       cti_deleteall() cancels all tests in the current test case.
  77 #
  78 #       cti_reportfile() writes the contents of a file to the journal.
  79 #
  80 #       cti_rmf() removes files.
  81 #
  82 #       cti_writefile() writes to the contents of a file;
  83 #       cti_appendfile() appends to contents of a file.
  84 #
  85 #       cti_execute() executes a command.
  86 #
  87 #       cti_runexpect() runs the expect utility. cti_expecttest() is
  88 #       like cti_runexpect() except that it is written with path tracing
  89 #       and is designed to do the complete work of a test purpose.
  90 #       cti_runexpect() runs the expect utility. cti_expecttest() is
  91 #       like cti_runexpect() except that it is written with path tracing
  92 #       and is designed to do the complete work of a test purpose.
  93 #
  94 #       cti_cancel() cancels the dedicated test purpose in the current test
  95 #       case from execution with the test result that user gives. It will work
  96 #       in startup function.
  97 #
  98 #       cti_cancelall() cancels all tests in the current test case. It could
  99 #       be used in startup function to cancel the execution of test cases
 100 #       with the test result that user gives.
 101 #
 102 ########################################################################
 103 
 104 #
 105 # cti_lf_checkargs() - check number of arguments passed to a shell function.
 106 #
 107 # Usage: cti_lf_checkargs argc expected-argc operator funcname
 108 #
 109 # operator can be EQ or GE.
 110 #
 111 # Returns 0 if the expected number of arguments were passed, non-zero
 112 # otherwise.
 113 #
 114 function cti_lf_checkargs
 115 {
 116         typeset -i cti_lv_argc=$1
 117         typeset -i cti_lv_expargc=$2
 118         typeset cti_lv_op="$3"
 119         typeset cti_lv_funcname="$4"
 120 
 121         case "$cti_lv_op" in
 122         EQ)
 123                 if test $cti_lv_argc -ne $cti_lv_expargc
 124                 then
 125                         cti_unresolved "Test coding error:" \
 126                                 "$cti_lv_funcname() called with $cti_lv_argc" \
 127                                 "args, need $cti_lv_expargc"
 128                         return 1
 129                 fi
 130                 ;;
 131         GE)
 132                 if test $cti_lv_argc -lt $cti_lv_expargc
 133                 then
 134                         cti_unresolved "Test coding error:" \
 135                                 "$cti_lv_funcname() called with $cti_lv_argc" \
 136                                 "args, need >= $cti_lv_expargc"
 137                         return 1
 138                 fi
 139                 ;;
 140         *)
 141                 cti_unresolved "Internal error: cti_lf_checkargs()" \
 142                         "called for $funcname() with operator $cti_lv_op"
 143                 return 1
 144                 ;;
 145         esac
 146 
 147         return 0
 148 }
 149 
 150 #
 151 # cti_result() - register a result and write informational line to journal.
 152 #
 153 # Usage: cti_result result [msg ...]
 154 #
 155 # If the current test function is not a startup or cleanup, this routine
 156 # registers the specified result code for the current test. The remaining
 157 # arguments, if any, are written to the execution results file as a single
 158 # line.
 159 #
 160 # Modifications for test-runner:
 161 # Print the result and test name (in place of tet_result)
 162 # On failure, return non-zero to tell test-runner our status.
 163 #
 164 function cti_result
 165 {
 166         typeset res
 167         typeset -i rv=0
 168 
 169         test $# -eq 0 && return
 170         res=$1
 171         shift
 172 
 173         my_host=`hostname`
 174         my_timestamp=`date | awk '{print $4}'`
 175 
 176         test $# -gt 0 && print "$my_host $my_timestamp $@"
 177 
 178         # Print the result and test name (as tet_result would)
 179         print "$res: ${tc_id:-$(basename $0)}"
 180 
 181         # Return non-zero for failures.  See codes in:
 182         # test-runner/stf/include/stf.shlib
 183         case "$res" in
 184         PASS)
 185                 ;;
 186         FAIL)
 187                 rv=1
 188                 ;;
 189         UNRESOLVED)
 190                 rv=2
 191                 ;;
 192         NOTINUSE)
 193                 rv=3
 194                 ;;
 195         UNSUPPORTED)
 196                 rv=4
 197                 ;;
 198         UNTESTED)
 199                 rv=5
 200                 ;;
 201         UNINITIATED)
 202                 rv=6
 203                 ;;
 204         NORESULT)
 205                 rv=7
 206                 ;;
 207         WARNING)
 208                 rv=8
 209                 ;;
 210         TIMED_OUT)
 211                 rv=9
 212                 ;;
 213         *)
 214                 echo "cti_result: $res: unknown result code"
 215                 rv=10
 216                 ;;
 217         esac
 218         return $rv
 219 }
 220 
 221 #
 222 # cti_report() - write an informational line to the journal
 223 #
 224 # Usage: cti_report arg ...
 225 #
 226 # Writes the arguments to the execution results file, as a single line.
 227 #
 228 function cti_report
 229 {
 230         my_host=`hostname`
 231         my_timestamp=`date | awk '{print $4}'`
 232 
 233         print "$my_host $my_timestamp $@"
 234 }
 235 
 236 #
 237 # cti_assert() - write an Assert line to the journal
 238 #
 239 # Usage: cti_assert assertion_number assertion_msg
 240 #
 241 # Writes the arguments to the execution results file, as a single line.
 242 #
 243 function cti_assert
 244 {
 245         cti_lf_checkargs $# 2 GE cti_assert || return 1
 246 
 247         cti_report "ASSERT $1: $2"
 248 }
 249 
 250 #
 251 # cti_pass() - register a PASS result.
 252 #
 253 # Usage: cti_pass [msg ...]
 254 #
 255 function cti_pass
 256 {
 257         cti_result PASS "$@"
 258 }
 259 
 260 #
 261 # cti_fail() - register a FAIL result.
 262 #
 263 # Usage: cti_fail [msg ...]
 264 #
 265 # Registers a FAIL result for the current test, and writes any arguments to
 266 # the execution results file, as a single line.
 267 #
 268 function cti_fail
 269 {
 270         cti_result FAIL "$@"
 271 }
 272 
 273 #
 274 # cti_unresolved() - register an UNRESOLVED result.
 275 #
 276 # Usage: cti_unresolved [msg ...]
 277 #
 278 # Registers an UNRESOLVED result for the current test, and writes any arguments
 279 # to the execution results file, as a single line.
 280 #
 281 function cti_unresolved
 282 {
 283         cti_result UNRESOLVED "$@"
 284 }
 285 
 286 
 287 #
 288 # cti_uninitiated() - register an UNINITIATED result.
 289 #
 290 # Usage: cti_uninitiated [msg ...]
 291 #
 292 # Registers an UNINITIATED result for the current test, and writes any arguments
 293 # to the execution results file, as a single line.
 294 #
 295 function cti_uninitiated
 296 {
 297         cti_result UNINITIATED "$@"
 298 }
 299 
 300 #
 301 # cti_untested() - register an UNTESTED result.
 302 #
 303 # Usage: cti_untested [msg ...]
 304 #
 305 # Registers an UNTESTED result for the current test, and writes any arguments
 306 # to the execution results file, as a single line.
 307 #
 308 function cti_untested
 309 {
 310         cti_result UNTESTED "$@"
 311 }
 312 
 313 #
 314 # cti_unsupported() - register an UNSUPPORTED result.
 315 #
 316 # Usage: cti_unsupported [msg ...]
 317 #
 318 # Registers an UNSUPPORTED result for the current test, and writes any
 319 # arguments to the execution results file, as a single line.
 320 #
 321 function cti_unsupported
 322 {
 323         cti_result UNSUPPORTED "$@"
 324 }
 325 
 326 #
 327 # cti_notinuse() - register a NOTINUSE result.
 328 #
 329 # Usage: cti_notinuse [msg ...]
 330 #
 331 # Registers a NOTINUSE result for the current test, and writes any arguments
 332 # to the execution results file, as a single line.
 333 #
 334 function cti_notinuse
 335 {
 336         cti_result NOTINUSE "$@"
 337 }
 338 
 339 #
 340 # cti_pathtrace() - increment path counter.
 341 #
 342 # Usage: cti_pathtrace
 343 #
 344 # Increments variable pathok. Like C macro PATH_TRACE.
 345 #
 346 function cti_pathtrace
 347 {
 348         : $((pathok += 1))
 349 }
 350 
 351 #
 352 # cti_checkpath() - check path tracing and register a PASS result.
 353 #
 354 # Usage: cti_checkpath expected-path-count
 355 #
 356 # Like C macro PATH_XS_RPT().
 357 #
 358 function cti_checkpath
 359 {
 360         cti_lf_checkargs $# 1 EQ cti_checkpath || return
 361 
 362         if test $pathok -eq $1
 363         then
 364                 cti_pass
 365         else
 366                 cti_unresolved "Path tracing error: path counter $pathok," \
 367                         "expecting $1"
 368         fi
 369 }
 370 
 371 #
 372 # cti_deleteall() - cancel all tests.
 373 #
 374 # Usage: cti_deleteall reason
 375 #
 376 # Cancels all tests
 377 #
 378 function cti_deleteall
 379 {
 380         typeset cti_lv_ic
 381         typeset cti_lv_tp
 382 
 383         test $# -eq 0 && return
 384 
 385         for cti_lv_ic in $iclist
 386         do
 387                 for cti_lv_tp in `eval echo \\$$cti_lv_ic`
 388                 do
 389                         if test -n "$cti_lv_tp"
 390                         then
 391                                 echo "Deleted test: $cti_lv_tp" "$@"
 392                         fi
 393                 done
 394         done
 395 }
 396 
 397 #
 398 # cti_reportfile() - write the contents of a file to the journal.
 399 #
 400 # Usage: cti_reportfile path [title]
 401 #
 402 # Writes the contents of the file specified by path to the execution results
 403 # file, line by line.
 404 #
 405 function cti_reportfile
 406 {
 407         typeset cti_lv_path=$1
 408         typeset cti_lv_title="${2:-$cti_lv_path}"
 409         typeset cti_lv_line
 410 
 411         cti_lf_checkargs $# 1 GE cti_reportfile || return
 412 
 413         cti_report "+++ $cti_lv_title +++"
 414 
 415         /usr/bin/cat $cti_lv_path
 416 
 417         cti_report "+++ end +++"
 418         cti_report " "
 419 }
 420 
 421 #
 422 # cti_rmf() - remove files.
 423 #
 424 # Usage: cti_rmf [files...]
 425 #
 426 # Calls "rm -f" to remove the files, and verifies that they have been removed.
 427 #
 428 # Returns 0 on success, non-zero if any of the files could not be removed.
 429 #
 430 function cti_rmf
 431 {
 432         typeset cti_lv_file
 433 
 434         for cti_lv_file in "$@"
 435         do
 436                 rm -f "$cti_lv_file"
 437 
 438                 if test -f "$cti_lv_file"
 439                 then
 440                         cti_unresolved "Error removing file \"$cti_lv_file\""
 441                         return 1
 442                 fi
 443         done
 444 
 445         return 0
 446 }
 447 
 448 #
 449 # cti_writefile() - write contents of a file.
 450 #
 451 # Usage: cti_writefile path mode lines...
 452 #
 453 # Truncates the file specified by path and then writes the third and
 454 # subsequent arguments to the specified file as separate lines.
 455 #
 456 # Returns 0 on success, non-zero if any of the files could not be removed.
 457 #
 458 function cti_writefile
 459 {
 460         cti_lf_checkargs $# 3 GE cti_writefile || return 1
 461 
 462         cti_rmf "$1" || return 1
 463         cti_appendfile "$@"
 464 }
 465 
 466 #
 467 # cti_appendfile() - append to contents of a file.
 468 #
 469 # Usage: cti_appendfile path mode lines...
 470 #
 471 # Appends the third and subsequent arguments to the specified file as separate
 472 # lines.
 473 #
 474 # Returns 0 on success, non-zero if any of the files could not be removed.
 475 #
 476 function cti_appendfile
 477 {
 478         typeset cti_lv_path="$1"
 479         typeset cti_lv_mode="$2"
 480         typeset cti_lv_line
 481 
 482         cti_lf_checkargs $# 3 GE cti_appendfile || return 1
 483         shift 2
 484 
 485         for cti_lv_line in "$@"
 486         do
 487                 echo "$cti_lv_line" >> "$cti_lv_path"
 488 
 489                 if [[ $? -ne 0 ]]
 490                 then
 491                         cti_unresolved \
 492                                 "Error writing to file \"$cti_lv_path\""
 493                         return 1
 494                 fi
 495         done
 496 
 497         cti_execute UNRESOLVED chmod "$cti_lv_mode" "$cti_lv_path"
 498         return $?
 499 }
 500 
 501 #
 502 # cti_execute() - execute a command
 503 #
 504 # Usage: cti_execute [-c out|err] [-i input] result cmd [args...]
 505 #
 506 # Executes a command. The standard output is redirected to the file cti_stdout
 507 # and the standard error is redirected to the file cti_stderr.
 508 #
 509 # If the command has a non-zero exit status, cti_execute() registers a result
 510 # code of `result'.
 511 #
 512 # Options:
 513 #       -c out|err      Check standard output/error. If anything is written to
 514 #                       the specified output channel, a result code of `result'
 515 #                       is registered and the output written to the journal.
 516 #                       May have multiple -c options.
 517 #       -i input        Use -i as an input line to the command.
 518 #                       May have multiple -i options.
 519 #
 520 # Returns 0 on success, non-zero on failure (returning the
 521 #  exit status from the command when possible).
 522 #
 523 function cti_execute
 524 {
 525         typeset cti_lv_opt
 526         typeset -i cti_lv_checkstdout=0
 527         typeset -i cti_lv_checkstderr=0
 528         typeset cti_lv_result
 529         typeset -i cti_lv_status
 530         typeset -i cti_lv_rv=0
 531 
 532         # Remove files used for redirecting standard I/O.
 533         cti_rmf cti_stdin cti_stdout cti_stderr || return 1
 534 
 535         # Create (empty) files to take standard output and error so there are
 536         # no problems later when we come to run the command.
 537         touch cti_stdout cti_stderr
 538 
 539         if [[ $? -ne 0 ]]
 540         then
 541                 cti_unresolved "Error creating files cti_stdout and cti_stderr"
 542                 return 1
 543         fi
 544 
 545         # Parse command line options
 546         while getopts "c:i:l:s:" cti_lv_opt
 547         do
 548                 case $cti_lv_opt in
 549                 c)
 550                         case "$OPTARG" in
 551                         out|err)
 552                                 eval cti_lv_checkstd$OPTARG=1
 553                                 ;;
 554                         *)
 555                                 cti_unresolved "cti_execute() called with" \
 556                                         "bad option argument -c $OPTARG"
 557                                 return 1
 558                                 ;;
 559                         esac
 560                         ;;
 561                 i)
 562                         echo "$OPTARG" >> cti_stdin
 563                         if [[ $? -ne 0 ]]
 564                         then
 565                                 cti_unresolved "Error writing to cti_stdin"
 566                                 return 1
 567                         fi
 568                         ;;
 569                 *)
 570                         cti_unresolved "cti_execute() called with illegal" \
 571                                 "option $cti_lv_opt"
 572                         return 1
 573                         ;;
 574                 esac
 575         done
 576 
 577         shift $((OPTIND-1))
 578 
 579         # Verify the correct number of arguments were passed.
 580         cti_lf_checkargs $# 2 GE cti_execute || return 1
 581 
 582         # First (non-option) argument is the result code to use if the command
 583         # fails.
 584         cti_lv_result="${1:-UNRESOLVED}"
 585         shift
 586 
 587         # Execute the command, redirecting standard input if required.
 588         if test -f cti_stdin
 589         then
 590                 eval "$@" < cti_stdin > cti_stdout 2> cti_stderr
 591         else
 592                 eval "$@" > cti_stdout 2> cti_stderr
 593         fi
 594 
 595         cti_lv_status=$?
 596 
 597         # Check the exit status of the command
 598         if test $cti_lv_status -ne 0
 599         then
 600                 if [[ "$cti_lv_result" = "CTI" ]]
 601                 then
 602                         cti_report CTI "Command \"$*\" failed "\
 603                                 "with status $cti_lv_status"
 604                 else
 605                         cti_result "$cti_lv_result"\
 606                                 "Command \"$*\" failed "\
 607                                 "with status $cti_lv_status"
 608                         cti_lv_rv=$cti_lv_status
 609                 fi
 610         fi
 611 
 612         # Always log output of cti_execute_cmd
 613         if [[ "$cti_lv_result" = "CTI" ]]
 614         then
 615 
 616                 if test -s cti_stdout
 617                 then
 618                         cti_reportfile cti_stdout "Standard output from command \"$*\""
 619                 fi
 620                 if test -s cti_stderr
 621                 then
 622                         cti_reportfile cti_stderr "Standard error from command \"$*\""
 623                 fi
 624                 return $cti_lv_status
 625         fi
 626 
 627         # If cmd failed, or if "-c err", check standard error.
 628         if test \( $cti_lv_rv -ne 0 -o $cti_lv_checkstderr -eq 1 \) \
 629                 -a -s cti_stderr
 630         then
 631                 cti_result "$cti_lv_result" \
 632                         "Command \"$*\" produced standard error"
 633                 cti_reportfile cti_stderr "Standard error from command \"$*\""
 634                 [[ $cti_lv_rv = 0 ]] && cti_lv_rv=1
 635         fi
 636 
 637         #  If cmd failed, or if "-c out", check standard output.
 638         if test \( $cti_lv_rv -ne 0 -o $cti_lv_checkstdout -eq 1 \) \
 639                 -a -s cti_stdout
 640         then
 641                 cti_result "$cti_lv_result" \
 642                         "Command \"$*\" produced standard output"
 643                 cti_reportfile cti_stdout "Standard output from command \"$*\""
 644                 [[ $cti_lv_rv = 0 ]] && cti_lv_rv=1
 645         fi
 646 
 647         return $cti_lv_rv
 648 }
 649 
 650 #
 651 # Exit values for expect scripts.
 652 # N.B. Do not use 0, as expect uses this for e.g. syntax errors.
 653 #
 654 typeset -ri CTI_EXP_RV_TIMEDOUT=1
 655 typeset -ri CTI_EXP_RV_TESTFAIL=2
 656 typeset -ri CTI_EXP_RV_OK=3
 657 
 658 #
 659 # cti_runexpect() - run the expect utility.
 660 #
 661 # Usage: cti_runexpect failtext command pattern action [pattern action ...]
 662 #
 663 # Executes the expect utility using the command line specified in the second
 664 # argument. Generates a temporary expect script which is removed at the end of
 665 # the call. The arguments following the second are pattern-action pairs. The
 666 # pattern can be a regular expression or "CALL", which indicates the action is
 667 # simply a function call which is unconditionally executed at that point.
 668 #
 669 # The following expect functions are available:
 670 #
 671 #       startcritical   Indicates that failures from this point onwards
 672 #                       constitute a test failure. In that case the
 673 #                       ``failtext'' argument is used to report the error
 674 #                       message.
 675 #       endcritical     Indicates the end of the test failure section begun by
 676 #                       startcritical.
 677 #       finish          Exit the expect script here - the test has passed.
 678 #
 679 # Returns 0 on success, non-zero on failure.
 680 #
 681 function cti_runexpect
 682 {
 683         typeset -ri CTI_EXP_TIMEOUT=5
 684         typeset -r cti_lv_expfile="./cti_$tc_id-$$.exp"
 685         typeset cti_lv_failtext="$1"
 686         typeset cti_lv_command="$2"
 687         typeset -i cti_lv_rv=0
 688         typeset cti_lv_dopt
 689 
 690         # Verify the correct number of arguments were passed.
 691         cti_lf_checkargs $# 4 GE cti_runexpect || return 1
 692 
 693         shift 2
 694 
 695         # Generate expect script.
 696         {
 697         echo "set STATUS_OK       $CTI_EXP_RV_OK"
 698         echo "set STATUS_FAIL     $CTI_EXP_RV_TESTFAIL"
 699         echo "set STATUS_TIMEDOUT $CTI_EXP_RV_TIMEDOUT"
 700         echo ''
 701         echo "set timeout $CTI_EXP_TIMEOUT"
 702         echo 'set retval $STATUS_TIMEDOUT'
 703         echo ''
 704         echo 'eval spawn [lrange $argv 0 end]'
 705         echo ''
 706         echo 'proc startcritical {} {'
 707         echo '  global retval'
 708         echo '  global STATUS_FAIL'
 709         echo '  set retval $STATUS_FAIL'
 710         echo '}'
 711         echo ''
 712         echo 'proc endcritical {} {'
 713         echo '  global retval'
 714         echo '  global STATUS_TIMEDOUT'
 715         echo '  set retval $STATUS_TIMEDOUT'
 716         echo '}'
 717         echo ''
 718         echo 'proc finish {} {'
 719         echo '  global STATUS_OK'
 720         echo '  exit $STATUS_OK'
 721         echo '}'
 722 
 723         while test $# -gt 1
 724         do
 725                 echo ''
 726 
 727                 if test "$1" = "CALL"
 728                 then
 729                         echo "$2"
 730                 else
 731                         echo 'expect {'
 732                         echo "  -re \"$1\" {"
 733                         echo "          $2 "
 734                         echo '  }'
 735                         echo '  timeout {'
 736                         echo '          exit $retval'
 737                         echo '  }'
 738                         echo '}'
 739                 fi
 740 
 741                 shift 2
 742         done
 743         } > $cti_lv_expfile
 744 
 745         # Check that there were no errors writing to the script file.
 746         if test $? -ne 0
 747         then
 748                 cti_unresolved "Error writing expect script to file" \
 749                         "\"$cti_lv_expfile\""
 750                 return 1
 751         fi
 752 
 753         # If debug is on, turn on expect debug flag.
 754         case "$CTI_SHELL_DEBUG" in
 755         y*|Y*)
 756                 cti_lv_dopt='-d'
 757                 ;;
 758         esac
 759 
 760         # Execute expect using generated script.
 761         expect $cti_lv_dopt -f $cti_lv_expfile $cti_lv_command > cti_expout 2>&1
 762         cti_lv_rv=$?
 763 
 764         # If debug is on, save expect script and output, otherwise remove
 765         # script.
 766         case "$CTI_SHELL_DEBUG" in
 767         y*|Y*)
 768                 cp cti_expout ${cti_lv_expfile%.exp}.out
 769                 cti_report "DEBUG: expect script is $PWD/$cti_lv_expfile," \
 770                         "expect output is in $PWD/${cti_lv_expfile%.exp}.out"
 771                 ;;
 772         *)
 773                 rm -f $cti_lv_expfile
 774         esac
 775 
 776         # Deal with return value from expect.
 777         case $cti_lv_rv in
 778         $CTI_EXP_RV_OK)
 779                 return 0
 780                 ;;
 781         $CTI_EXP_RV_TIMEDOUT)
 782                 cti_unresolved "Expect script timed-out during test setup"
 783                 ;;
 784         $CTI_EXP_RV_TESTFAIL)
 785                 cti_fail "$cti_lv_failtext"
 786                 ;;
 787         *)
 788                 cti_unresolved "Test coding error or expect bug:" \
 789                         "unexpected exit status $cti_lv_rv from expect script"
 790                 cti_reportfile cti_expout "Output from expect"
 791                 ;;
 792         esac
 793 
 794         return 1
 795 }
 796 
 797 #
 798 # cti_expecttest() - run the expect utility.
 799 #
 800 # Usage: cti_expecttest failtext command pattern action [pattern action ...]
 801 #
 802 # Common test function for test purposes which use expect. Like cti_runexpect()
 803 # except that this is written with path tracing and is designed to do the
 804 # complete work of a test purpose.
 805 #
 806 function cti_expecttest
 807 {
 808         # Verify the correct number of arguments were passed.
 809         cti_lf_checkargs $# 4 GE cti_expecttest || return
 810 
 811         # Use cti_runexpect() to execute expect utililty.
 812         if cti_runexpect "$@"
 813         then
 814                 cti_pathtrace
 815         else
 816                 return
 817         fi
 818 
 819         cti_checkpath 1
 820 }
 821 
 822 function cti_execute_cmd
 823 {
 824         cti_execute CTI "$@"
 825 }
 826 
 827 #
 828 # "private" functions for internal use by cti_cancel function
 829 # used to replace test purpose functions which will be canceled.
 830 #
 831 function cancel_ic {
 832         cti_result $cticancel_result "$cticancel_msg"
 833 }
 834 
 835 #
 836 # cti_cancel() - cancel an individual test purpose.
 837 #
 838 # Usage: cti_cancel tp reason [test result]
 839 #
 840 # Cancels an individual test by replace the tp function with
 841 # cancel_ic function
 842 #
 843 function cti_cancel {
 844         test $# -gt 3 && return
 845         test_num=$1
 846         cticancel_msg="$2"
 847         cticancel_result=${3:-"UNSUPPORTED"}
 848         typeset cti_lv_ic cti_lv_ic_mod
 849         typeset cti_lv_tp
 850 
 851         cti_report "Canceling test $test_num: $cticancel_msg"
 852         #
 853         # translate the ic and point the test purpose ic to
 854         # cancel_ic function
 855         #
 856         for cti_lv_ic in $iclist
 857         do
 858                 cti_lv_ic_mod=""
 859                 for cti_lv_tp in `eval echo \\$$cti_lv_ic`
 860                 do
 861                         if [ X"$cti_lv_tp" == X"$test_num" ]; then
 862                                 cti_lv_ic_mod=$cti_lv_ic_mod" cancel_ic"
 863                         else
 864                                 cti_lv_ic_mod=$cti_lv_ic_mod" $cti_lv_tp"
 865                         fi
 866                 done
 867                 eval "$cti_lv_ic=\"$cti_lv_ic_mod\""
 868         done
 869 }
 870 
 871 #
 872 # cti_cancelall() - cancel all tests.
 873 #
 874 # Usage: cti_cancelall reason [test result]
 875 #
 876 # Cancels all tests by replace the tests functions with cancel_ic function
 877 #
 878 function cti_cancelall {
 879         typeset cti_lv_ic
 880         typeset cti_lv_tp
 881         cticancel_msg=$1
 882         cticancel_result=${2:-"UNSUPPORTED"}
 883 
 884         test $# -eq 0 && return
 885 
 886         for cti_lv_ic in $iclist
 887         do
 888                 for cti_lv_tp in `eval echo \\$$cti_lv_ic`
 889                 do
 890                         cti_cancel $cti_lv_tp "$cticancel_msg" \
 891                             $cticancel_result
 892                 done
 893         done
 894 }