1#!/bin/sh 2# SPDX-License-Identifier: GPL-2.0-only 3 4# ftracetest - Ftrace test shell scripts 5# 6# Copyright (C) Hitachi Ltd., 2014 7# Written by Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> 8# 9 10# Keep command output parsing stable regardless of the user's locale. 11export LC_ALL=C 12 13usage() { # errno [message] 14[ ! -z "$2" ] && echo $2 15echo "Usage: ftracetest [options] [testcase(s)] [testcase-directory(s)]" 16echo " Options:" 17echo " -h|--help Show help message" 18echo " -k|--keep Keep passed test logs" 19echo " -K|--ktap Output in KTAP format" 20echo " -v|--verbose Increase verbosity of test messages" 21echo " -vv Alias of -v -v (Show all results in stdout)" 22echo " -vvv Alias of -v -v -v (Show all commands immediately)" 23echo " --fail-unsupported Treat UNSUPPORTED as a failure" 24echo " --fail-unresolved Treat UNRESOLVED as a failure" 25echo " -d|--debug Debug mode (trace all shell commands)" 26echo " -l|--logdir <dir> Save logs on the <dir>" 27echo " If <dir> is -, all logs output in console only" 28echo " --rv Run RV selftests instead of ftrace ones" 29exit $1 30} 31 32# default error 33err_ret=1 34 35# kselftest skip code is 4 36err_skip=4 37 38# umount required 39UMOUNT_DIR="" 40 41# cgroup RT scheduling prevents chrt commands from succeeding, which 42# induces failures in test wakeup tests. Disable for the duration of 43# the tests. 44 45readonly sched_rt_runtime=/proc/sys/kernel/sched_rt_runtime_us 46 47sched_rt_runtime_orig=$(cat $sched_rt_runtime) 48 49setup() { 50 echo -1 > $sched_rt_runtime 51} 52 53cleanup() { 54 echo $sched_rt_runtime_orig > $sched_rt_runtime 55 if [ -n "${UMOUNT_DIR}" ]; then 56 umount ${UMOUNT_DIR} ||: 57 fi 58} 59 60errexit() { # message 61 echo "Error: $1" 1>&2 62 cleanup 63 exit $err_ret 64} 65 66# Ensuring user privilege 67if [ `id -u` -ne 0 ]; then 68 errexit "this must be run by root user" 69fi 70 71setup 72 73# Utilities 74absdir() { # file_path 75 (cd `dirname $1`; pwd) 76} 77 78abspath() { 79 echo `absdir $1`/`basename $1` 80} 81 82find_testcases() { #directory 83 echo `find $1 -name \*.tc | sort` 84} 85 86parse_opts() { # opts 87 local OPT_TEST_CASES= 88 local OPT_TEST_DIR= 89 90 while [ ! -z "$1" ]; do 91 case "$1" in 92 --help|-h) 93 usage 0 94 ;; 95 --keep|-k) 96 KEEP_LOG=1 97 shift 1 98 ;; 99 --ktap|-K) 100 KTAP=1 101 shift 1 102 ;; 103 --verbose|-v|-vv|-vvv) 104 if [ $VERBOSE -eq -1 ]; then 105 usage "--console can not use with --verbose" 106 fi 107 VERBOSE=$((VERBOSE + 1)) 108 [ $1 = '-vv' ] && VERBOSE=$((VERBOSE + 1)) 109 [ $1 = '-vvv' ] && VERBOSE=$((VERBOSE + 2)) 110 shift 1 111 ;; 112 --console) 113 if [ $VERBOSE -ne 0 ]; then 114 usage "--console can not use with --verbose" 115 fi 116 VERBOSE=-1 117 shift 1 118 ;; 119 --debug|-d) 120 DEBUG=1 121 shift 1 122 ;; 123 --stop-fail) 124 STOP_FAILURE=1 125 shift 1 126 ;; 127 --fail-unsupported) 128 UNSUPPORTED_RESULT=1 129 shift 1 130 ;; 131 --fail-unresolved) 132 UNRESOLVED_RESULT=1 133 shift 1 134 ;; 135 --logdir|-l) 136 USER_LOG_DIR=$2 137 shift 2 138 ;; 139 --rv) 140 RV_TEST=1 141 shift 1 142 ;; 143 *.tc) 144 if [ -f "$1" ]; then 145 OPT_TEST_CASES="$OPT_TEST_CASES `abspath $1`" 146 shift 1 147 else 148 usage 1 "$1 is not a testcase" 149 fi 150 ;; 151 *) 152 if [ -d "$1" ]; then 153 OPT_TEST_DIR=`abspath $1` 154 OPT_TEST_CASES="$OPT_TEST_CASES `find_testcases $OPT_TEST_DIR`" 155 shift 1 156 else 157 usage 1 "Invalid option ($1)" 158 fi 159 ;; 160 esac 161 done 162 if [ -n "$OPT_TEST_CASES" ]; then 163 TEST_CASES=$OPT_TEST_CASES 164 fi 165 if [ -n "$OPT_TEST_DIR" -a -f "$OPT_TEST_DIR"/test.d/functions ]; then 166 TOP_DIR=$OPT_TEST_DIR 167 TEST_DIR=$TOP_DIR/test.d 168 fi 169} 170 171# Parameters 172TRACING_DIR=`grep tracefs /proc/mounts | cut -f2 -d' ' | head -1` 173if [ -z "$TRACING_DIR" ]; then 174 DEBUGFS_DIR=`grep debugfs /proc/mounts | cut -f2 -d' ' | head -1` 175 if [ -z "$DEBUGFS_DIR" ]; then 176 # If tracefs exists, then so does /sys/kernel/tracing 177 if [ -d "/sys/kernel/tracing" ]; then 178 mount -t tracefs nodev /sys/kernel/tracing || 179 errexit "Failed to mount /sys/kernel/tracing" 180 TRACING_DIR="/sys/kernel/tracing" 181 UMOUNT_DIR=${TRACING_DIR} 182 # If debugfs exists, then so does /sys/kernel/debug 183 elif [ -d "/sys/kernel/debug" ]; then 184 mount -t debugfs nodev /sys/kernel/debug || 185 errexit "Failed to mount /sys/kernel/debug" 186 TRACING_DIR="/sys/kernel/debug/tracing" 187 UMOUNT_DIR=${TRACING_DIR} 188 else 189 err_ret=$err_skip 190 errexit "debugfs and tracefs are not configured in this kernel" 191 fi 192 else 193 TRACING_DIR="$DEBUGFS_DIR/tracing" 194 fi 195fi 196if [ ! -d "$TRACING_DIR" ]; then 197 err_ret=$err_skip 198 errexit "ftrace is not configured in this kernel" 199fi 200 201TOP_DIR=`absdir $0` 202TEST_DIR=$TOP_DIR/test.d 203TEST_CASES=`find_testcases $TEST_DIR` 204USER_LOG_DIR= 205KEEP_LOG=0 206KTAP=0 207DEBUG=0 208VERBOSE=0 209UNSUPPORTED_RESULT=0 210UNRESOLVED_RESULT=0 211STOP_FAILURE=0 212RV_TEST=0 213# Parse command-line options 214parse_opts $* 215 216[ $DEBUG -ne 0 ] && set -x 217 218# TOP_DIR can be changed for rv. Setting log directory. 219LOG_TOP_DIR=$TOP_DIR/logs 220LOG_DATE=`date +%Y%m%d-%H%M%S` 221if [ -n "$USER_LOG_DIR" ]; then 222 LOG_DIR=$USER_LOG_DIR 223 LINK_PTR= 224else 225 LOG_DIR=$LOG_TOP_DIR/$LOG_DATE/ 226 LINK_PTR=$LOG_TOP_DIR/latest 227fi 228 229if [ $RV_TEST -ne 0 ]; then 230 TRACING_DIR=$TRACING_DIR/rv 231 if [ ! -d "$TRACING_DIR" ]; then 232 err_ret=$err_skip 233 errexit "rv is not configured in this kernel" 234 fi 235fi 236 237# Preparing logs 238if [ "x$LOG_DIR" = "x-" ]; then 239 LOG_FILE= 240 date 241else 242 LOG_FILE=$LOG_DIR/ftracetest.log 243 mkdir -p $LOG_DIR || errexit "Failed to make a log directory: $LOG_DIR" 244 date > $LOG_FILE 245 if [ "x-$LINK_PTR" != "x-" ]; then 246 unlink $LINK_PTR 247 ln -fs $LOG_DATE $LINK_PTR 248 fi 249fi 250 251# Define text colors 252# Check available colors on the terminal, if any 253ncolors=`tput colors 2>/dev/null || echo 0` 254color_reset= 255color_red= 256color_green= 257color_blue= 258# If stdout exists and number of colors is eight or more, use them 259if [ -t 1 -a "$ncolors" -ge 8 ]; then 260 color_reset="\033[0m" 261 color_red="\033[31m" 262 color_green="\033[32m" 263 color_blue="\033[34m" 264fi 265 266strip_esc() { 267 # busybox sed implementation doesn't accept "\x1B", so use [:cntrl:] instead. 268 sed -E "s/[[:cntrl:]]\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g" 269} 270 271prlog() { # messages 272 newline="\n" 273 if [ "$1" = "-n" ] ; then 274 newline= 275 shift 276 fi 277 [ "$KTAP" != "1" ] && printf "$*$newline" 278 [ "$LOG_FILE" ] && printf "$*$newline" | strip_esc >> $LOG_FILE 279} 280catlog() { #file 281 if [ "${KTAP}" = "1" ]; then 282 cat $1 | while read line ; do 283 echo "# $line" 284 done 285 else 286 cat $1 287 fi 288 [ "$LOG_FILE" ] && cat $1 | strip_esc >> $LOG_FILE 289} 290prlog "=== Ftrace unit tests ===" 291 292 293# Testcase management 294# Test result codes - Dejagnu extended code 295PASS=0 # The test succeeded. 296FAIL=1 # The test failed, but was expected to succeed. 297UNRESOLVED=2 # The test produced indeterminate results. (e.g. interrupted) 298UNTESTED=3 # The test was not run, currently just a placeholder. 299UNSUPPORTED=4 # The test failed because of lack of feature. 300XFAIL=5 # The test failed, and was expected to fail. 301 302# Accumulations 303PASSED_CASES= 304FAILED_CASES= 305UNRESOLVED_CASES= 306UNTESTED_CASES= 307UNSUPPORTED_CASES= 308XFAILED_CASES= 309UNDEFINED_CASES= 310TOTAL_RESULT=0 311 312INSTANCE= 313CASENO=0 314CASENAME= 315 316testcase() { # testfile 317 CASENO=$((CASENO+1)) 318 CASENAME=`grep "^#[ \t]*description:" $1 | cut -f2- -d:` 319} 320 321checkreq() { # testfile 322 requires=`grep "^#[ \t]*requires:" $1 | cut -f2- -d:` 323 # Use eval to pass quoted-patterns correctly. 324 eval check_requires "$requires" 325} 326 327test_on_instance() { # testfile 328 grep -q "^#[ \t]*flags:.*instance" $1 329} 330 331ktaptest() { # result comment 332 if [ "$KTAP" != "1" ]; then 333 return 334 fi 335 336 local result= 337 if [ "$1" = "1" ]; then 338 result="ok" 339 else 340 result="not ok" 341 fi 342 shift 343 344 local comment=$* 345 if [ "$comment" != "" ]; then 346 comment="# $comment" 347 fi 348 349 echo $result $CASENO $INSTANCE$CASENAME $comment 350} 351 352eval_result() { # sigval 353 case $1 in 354 $PASS) 355 prlog " [${color_green}PASS${color_reset}]" 356 ktaptest 1 357 PASSED_CASES="$PASSED_CASES $CASENO" 358 return 0 359 ;; 360 $FAIL) 361 prlog " [${color_red}FAIL${color_reset}]" 362 ktaptest 0 363 FAILED_CASES="$FAILED_CASES $CASENO" 364 return 1 # this is a bug. 365 ;; 366 $UNRESOLVED) 367 prlog " [${color_blue}UNRESOLVED${color_reset}]" 368 ktaptest 0 UNRESOLVED 369 UNRESOLVED_CASES="$UNRESOLVED_CASES $CASENO" 370 return $UNRESOLVED_RESULT # depends on use case 371 ;; 372 $UNTESTED) 373 prlog " [${color_blue}UNTESTED${color_reset}]" 374 ktaptest 1 SKIP 375 UNTESTED_CASES="$UNTESTED_CASES $CASENO" 376 return 0 377 ;; 378 $UNSUPPORTED) 379 prlog " [${color_blue}UNSUPPORTED${color_reset}]" 380 ktaptest 1 SKIP 381 UNSUPPORTED_CASES="$UNSUPPORTED_CASES $CASENO" 382 return $UNSUPPORTED_RESULT # depends on use case 383 ;; 384 $XFAIL) 385 prlog " [${color_green}XFAIL${color_reset}]" 386 ktaptest 1 XFAIL 387 XFAILED_CASES="$XFAILED_CASES $CASENO" 388 return 0 389 ;; 390 *) 391 prlog " [${color_blue}UNDEFINED${color_reset}]" 392 ktaptest 0 error 393 UNDEFINED_CASES="$UNDEFINED_CASES $CASENO" 394 return 1 # this must be a test bug 395 ;; 396 esac 397} 398 399# Signal handling for result codes 400SIG_RESULT= 401SIG_BASE=36 # Use realtime signals 402SIG_PID=$$ 403 404exit_pass () { 405 exit 0 406} 407 408SIG_FAIL=$((SIG_BASE + FAIL)) 409exit_fail () { 410 exit 1 411} 412trap 'SIG_RESULT=$FAIL' $SIG_FAIL 413 414SIG_UNRESOLVED=$((SIG_BASE + UNRESOLVED)) 415exit_unresolved () { 416 kill -s $SIG_UNRESOLVED $SIG_PID 417 exit 0 418} 419trap 'SIG_RESULT=$UNRESOLVED' $SIG_UNRESOLVED 420 421SIG_UNTESTED=$((SIG_BASE + UNTESTED)) 422exit_untested () { 423 kill -s $SIG_UNTESTED $SIG_PID 424 exit 0 425} 426trap 'SIG_RESULT=$UNTESTED' $SIG_UNTESTED 427 428SIG_UNSUPPORTED=$((SIG_BASE + UNSUPPORTED)) 429exit_unsupported () { 430 kill -s $SIG_UNSUPPORTED $SIG_PID 431 exit 0 432} 433trap 'SIG_RESULT=$UNSUPPORTED' $SIG_UNSUPPORTED 434 435SIG_XFAIL=$((SIG_BASE + XFAIL)) 436exit_xfail () { 437 kill -s $SIG_XFAIL $SIG_PID 438 exit 0 439} 440trap 'SIG_RESULT=$XFAIL' $SIG_XFAIL 441 442__run_test() { # testfile 443 # setup PID and PPID, $$ is not updated. 444 (cd $TRACING_DIR; read PID _ < /proc/self/stat; set -e; set -x; 445 checkreq $1; initialize_system; . $1) 446 [ $? -ne 0 ] && kill -s $SIG_FAIL $SIG_PID 447} 448 449# Run one test case 450run_test() { # testfile 451 local testname=`basename $1` 452 testcase $1 453 prlog -n "[$CASENO]$INSTANCE$CASENAME" 454 if [ ! -z "$LOG_FILE" ] ; then 455 local testlog=`mktemp $LOG_DIR/${CASENO}-${testname}-log.XXXXXX` 456 else 457 local testlog=/proc/self/fd/1 458 fi 459 export TMPDIR=`mktemp -d /tmp/ftracetest-dir.XXXXXX` 460 export FTRACETEST_ROOT=$TOP_DIR 461 echo "execute$INSTANCE: "$1 > $testlog 462 SIG_RESULT=0 463 if [ $VERBOSE -eq -1 ]; then 464 __run_test $1 465 elif [ -z "$LOG_FILE" ]; then 466 __run_test $1 2>&1 467 elif [ $VERBOSE -ge 3 ]; then 468 __run_test $1 | tee -a $testlog 2>&1 469 elif [ $VERBOSE -eq 2 ]; then 470 __run_test $1 2>> $testlog | tee -a $testlog 471 else 472 __run_test $1 >> $testlog 2>&1 473 fi 474 eval_result $SIG_RESULT 475 if [ $? -eq 0 ]; then 476 # Remove test log if the test was done as it was expected. 477 [ $KEEP_LOG -eq 0 -a ! -z "$LOG_FILE" ] && rm $testlog 478 else 479 [ $VERBOSE -eq 1 -o $VERBOSE -eq 2 ] && catlog $testlog 480 TOTAL_RESULT=1 481 fi 482 rm -rf $TMPDIR 483} 484 485# load in the helper functions 486. $TEST_DIR/functions 487 488if [ "$KTAP" = "1" ]; then 489 echo "TAP version 13" 490 491 casecount=`echo $TEST_CASES | wc -w` 492 for t in $TEST_CASES; do 493 test_on_instance $t || continue 494 casecount=$((casecount+1)) 495 done 496 echo "1..${casecount}" 497fi 498 499# Main loop 500for t in $TEST_CASES; do 501 run_test $t 502 if [ $STOP_FAILURE -ne 0 -a $TOTAL_RESULT -ne 0 ]; then 503 echo "A failure detected. Stop test." 504 exit 1 505 fi 506done 507 508# Test on instance loop 509(cd $TRACING_DIR; initialize_system) 510INSTANCE=" (instance) " 511for t in $TEST_CASES; do 512 test_on_instance $t || continue 513 SAVED_TRACING_DIR=$TRACING_DIR 514 export TRACING_DIR=`mktemp -d $TRACING_DIR/instances/ftracetest.XXXXXX` 515 run_test $t 516 rmdir $TRACING_DIR 517 TRACING_DIR=$SAVED_TRACING_DIR 518 if [ $STOP_FAILURE -ne 0 -a $TOTAL_RESULT -ne 0 ]; then 519 echo "A failure detected. Stop test." 520 exit 1 521 fi 522done 523(cd $TRACING_DIR; finish_system) # for cleanup 524 525prlog "" 526prlog "# of passed: " `echo $PASSED_CASES | wc -w` 527prlog "# of failed: " `echo $FAILED_CASES | wc -w` 528prlog "# of unresolved: " `echo $UNRESOLVED_CASES | wc -w` 529prlog "# of untested: " `echo $UNTESTED_CASES | wc -w` 530prlog "# of unsupported: " `echo $UNSUPPORTED_CASES | wc -w` 531prlog "# of xfailed: " `echo $XFAILED_CASES | wc -w` 532prlog "# of undefined(test bug): " `echo $UNDEFINED_CASES | wc -w` 533 534if [ "$KTAP" = "1" ]; then 535 echo -n "# Totals:" 536 echo -n " pass:"`echo $PASSED_CASES | wc -w` 537 echo -n " fail:"`echo $FAILED_CASES | wc -w` 538 echo -n " xfail:"`echo $XFAILED_CASES | wc -w` 539 echo -n " xpass:0" 540 echo -n " skip:"`echo $UNTESTED_CASES $UNSUPPORTED_CASES | wc -w` 541 echo -n " error:"`echo $UNRESOLVED_CASES $UNDEFINED_CASES | wc -w` 542 echo 543fi 544 545cleanup 546 547# if no error, return 0 548exit $TOTAL_RESULT 549