clear_trace() { # reset trace output
    echo > trace
}

disable_tracing() { # stop trace recording
    echo 0 > tracing_on
}

enable_tracing() { # start trace recording
    echo 1 > tracing_on
}

reset_tracer() { # reset the current tracer
    echo nop > current_tracer
}

reset_trigger_file() {
    # remove action triggers first
    grep -H ':on[^:]*(' $@ |
    while read line; do
        cmd=`echo $line | cut -f2- -d: | cut -f1 -d"["`
	file=`echo $line | cut -f1 -d:`
	echo "!$cmd" >> $file
    done
    grep -Hv ^# $@ |
    while read line; do
        cmd=`echo $line | cut -f2- -d: | cut -f1 -d"["`
	file=`echo $line | cut -f1 -d:`
	echo "!$cmd" > $file
    done
}

reset_trigger() { # reset all current setting triggers
    if [ -d events/synthetic ]; then
        reset_trigger_file events/synthetic/*/trigger
    fi
    reset_trigger_file events/*/*/trigger
}

reset_events_filter() { # reset all current setting filters
    grep -v ^none events/*/*/filter |
    while read line; do
	echo 0 > `echo $line | cut -f1 -d:`
    done
}

reset_ftrace_filter() { # reset all triggers in set_ftrace_filter
    if [ ! -f set_ftrace_filter ]; then
      return 0
    fi
    echo > set_ftrace_filter
    grep -v '^#' set_ftrace_filter | while read t; do
	tr=`echo $t | cut -d: -f2`
	if [ "$tr" = "" ]; then
	    continue
	fi
	if ! grep -q "$t" set_ftrace_filter; then
		continue;
	fi
	name=`echo $t | cut -d: -f1 | cut -d' ' -f1`
	if [ $tr = "enable_event" -o $tr = "disable_event" ]; then
	    tr=`echo $t | cut -d: -f2-4`
	    limit=`echo $t | cut -d: -f5`
	else
	    tr=`echo $t | cut -d: -f2`
	    limit=`echo $t | cut -d: -f3`
	fi
	if [ "$limit" != "unlimited" ]; then
	    tr="$tr:$limit"
	fi
	echo "!$name:$tr" > set_ftrace_filter
    done
}

disable_events() {
    echo 0 > events/enable
}

clear_synthetic_events() { # reset all current synthetic events
    grep -v ^# synthetic_events |
    while read line; do
        echo "!$line" >> synthetic_events
    done
}

clear_dynamic_events() { # reset all current dynamic events
    again=1
    stop=1
    # loop mulitple times as some events require other to be removed first
    while [ $again -eq 1 ]; do
	stop=$((stop+1))
	# Prevent infinite loops
	if [ $stop -gt 10 ]; then
	    break;
	fi
	again=2
	grep -v '^#' dynamic_events|
	while read line; do
	    del=`echo $line | sed -e 's/^.\([^ ]*\).*/-\1/'`
	    if ! echo "$del" >> dynamic_events; then
		again=1
	    fi
	done
    done
}

initialize_ftrace() { # Reset ftrace to initial-state
# As the initial state, ftrace will be set to nop tracer,
# no events, no triggers, no filters, no function filters,
# no probes, and tracing on.
    disable_tracing
    reset_tracer
    reset_trigger
    reset_events_filter
    reset_ftrace_filter
    disable_events
    clear_dynamic_events
    [ -f set_event_pid ] && echo > set_event_pid
    [ -f set_ftrace_pid ] && echo > set_ftrace_pid
    [ -f set_ftrace_notrace ] && echo > set_ftrace_notrace
    [ -f set_graph_function ] && echo | tee set_graph_*
    [ -f stack_trace_filter ] && echo > stack_trace_filter
    [ -f kprobe_events ] && echo > kprobe_events
    [ -f uprobe_events ] && echo > uprobe_events
    [ -f synthetic_events ] && echo > synthetic_events
    [ -f snapshot ] && echo 0 > snapshot

# Stop tracing while reading the trace file by default, to prevent
# the test results while checking it and to avoid taking a long time
# to check the result.
    [ -f options/pause-on-trace ] && echo 1 > options/pause-on-trace

    clear_trace
    enable_tracing
}

finish_ftrace() {
    initialize_ftrace
# And recover it to default.
    [ -f options/pause-on-trace ] && echo 0 > options/pause-on-trace
}

check_requires() { # Check required files and tracers
    for i in "$@" ; do
	p=${i%:program}
        r=${i%:README}
        t=${i%:tracer}
	if [ $p != $i ]; then
	    if ! which $p ; then
                echo "Required program $p is not found."
                exit_unresolved
	    fi
        elif [ $t != $i ]; then
            if ! grep -wq $t available_tracers ; then
                echo "Required tracer $t is not configured."
                exit_unsupported
            fi
        elif [ "$r" != "$i" ]; then
            if ! grep -Fq "$r" README ; then
                echo "Required feature pattern \"$r\" is not in README."
                exit_unsupported
            fi
        elif [ ! -e $i ]; then
            echo "Required feature interface $i doesn't exist."
            exit_unsupported
        fi
    done
}

LOCALHOST=127.0.0.1

yield() {
    ping $LOCALHOST -c 1 || sleep .001 || usleep 1 || sleep 1
}

# The fork function in the kernel was renamed from "_do_fork" to
# "kernel_fork". As older tests should still work with older kernels
# as well as newer kernels, check which version of fork is used on this
# kernel so that the tests can use the fork function for the running kernel.
FUNCTION_FORK=`(if grep '\bkernel_clone\b' /proc/kallsyms > /dev/null; then
                echo kernel_clone; else echo '_do_fork'; fi)`

# Since probe event command may include backslash, explicitly use printf "%s"
# to NOT interpret it.
ftrace_errlog_check() { # err-prefix command-with-error-pos-by-^ command-file
    pos=$(printf "%s" "${2%^*}" | wc -c) # error position
    command=$(printf "%s" "$2" | tr -d ^)
    echo "Test command: $command"
    echo > error_log
    (! printf "%s" "$command" >> "$3" ) 2> /dev/null
    grep "$1: error:" -A 3 error_log
    N=$(tail -n 1 error_log | wc -c)
    # "  Command: " and "^\n" => 13
    test $(expr 13 + $pos) -eq $N
}

# Helper to get the tracefs mount point
get_mount_point() {
	local mount_point=`stat -c '%m' .`

	# If stat -c '%m' does not work (e.g. busybox) or failed, try to use the
	# current working directory (which should be a tracefs) as the mount point.
	if [ ! -d "$mount_point" ]; then
		if mount | grep -qw "$PWD"; then
			mount_point=$PWD
		else
			# If PWD doesn't work, that is an environmental problem.
			exit_unresolved
		fi
	fi
	echo "$mount_point"
}

# Helper function to retrieve mount options for a given mount point
get_mnt_options() {
	local mnt_point="$1"
	local opts=$(mount | grep -m1 "$mnt_point" | sed -e 's/.*(\(.*\)).*/\1/')

	echo "$opts"
}