#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: ftrace - test reading of set_ftrace_filter
#
# The triggers are set within the set_ftrace_filter file
# requires: set_ftrace_filter
#
# The set_ftrace_filter file of ftrace is used to list functions as well as
# triggers (probes) attached to functions. The code to read this file is not
# straight forward and has had various bugs in the past. This test is designed
# to add functions and triggers to that file in various ways and read that
# file in various ways (cat vs dd).
#

fail() { # mesg
    echo $1
    exit_fail
}

FILTER=set_ftrace_filter
FUNC1="schedule"
if grep '^sched_tick\b' available_filter_functions; then
    FUNC2="sched_tick"
elif grep '^scheduler_tick\b' available_filter_functions; then
    FUNC2="scheduler_tick"
else
    exit_unresolved
fi


ALL_FUNCS="#### all functions enabled ####"

test_func() {
    if ! echo "$1" | grep -q "^$2\$"; then
	return 0
    fi
    echo "$1" | grep -v "^$2\$"
    return 1
}

check_set_ftrace_filter() {
    cat=`cat $FILTER`
    dd1=`dd if=$FILTER bs=1 | grep -v -e 'records in' -e 'records out' -e 'bytes copied'`
    dd100=`dd if=$FILTER bs=100 | grep -v -e 'records in' -e 'records out' -e 'bytes copied'`

    echo "Testing '$@'"

    while [ $# -gt 0 ]; do
	echo "test $1"
	if cat=`test_func "$cat" "$1"`; then
	    return 0
	fi
	if dd1=`test_func "$dd1" "$1"`; then
	    return 0
	fi
	if dd100=`test_func "$dd100" "$1"`; then
	    return 0
	fi
	shift
    done

    if [ -n "$cat" ]; then
	return 0
    fi
    if [ -n "$dd1" ]; then
	return 0
    fi
    if [ -n "$dd100" ]; then
	return 0
    fi
    return 1;
}

if check_set_ftrace_filter "$ALL_FUNCS"; then
    fail "Expected only $ALL_FUNCS"
fi

echo "$FUNC1:traceoff" > set_ftrace_filter
if check_set_ftrace_filter "$ALL_FUNCS" "$FUNC1:traceoff:unlimited"; then
    fail "Expected $ALL_FUNCS and $FUNC1:traceoff:unlimited"
fi

echo "$FUNC1" > set_ftrace_filter
if check_set_ftrace_filter "$FUNC1" "$FUNC1:traceoff:unlimited"; then
    fail "Expected $FUNC1 and $FUNC1:traceoff:unlimited"
fi

echo "$FUNC2" >> set_ftrace_filter
if check_set_ftrace_filter "$FUNC1" "$FUNC2" "$FUNC1:traceoff:unlimited"; then
    fail "Expected $FUNC1 $FUNC2 and $FUNC1:traceoff:unlimited"
fi

echo "$FUNC2:traceoff" >> set_ftrace_filter
if check_set_ftrace_filter "$FUNC1" "$FUNC2" "$FUNC1:traceoff:unlimited" "$FUNC2:traceoff:unlimited"; then
    fail "Expected $FUNC1 $FUNC2 $FUNC1:traceoff:unlimited and $FUNC2:traceoff:unlimited"
fi

echo "$FUNC1" > set_ftrace_filter
if check_set_ftrace_filter "$FUNC1" "$FUNC1:traceoff:unlimited" "$FUNC2:traceoff:unlimited"; then
    fail "Expected $FUNC1 $FUNC1:traceoff:unlimited and $FUNC2:traceoff:unlimited"
fi

echo > set_ftrace_filter
if check_set_ftrace_filter "$ALL_FUNCS" "$FUNC1:traceoff:unlimited" "$FUNC2:traceoff:unlimited"; then
    fail "Expected $ALL_FUNCS $FUNC1:traceoff:unlimited and $FUNC2:traceoff:unlimited"
fi

reset_ftrace_filter

if check_set_ftrace_filter "$ALL_FUNCS"; then
    fail "Expected $ALL_FUNCS"
fi

echo "$FUNC1" > set_ftrace_filter
if check_set_ftrace_filter "$FUNC1" ; then
    fail "Expected $FUNC1"
fi

echo "$FUNC2" >> set_ftrace_filter
if check_set_ftrace_filter "$FUNC1" "$FUNC2" ; then
    fail "Expected $FUNC1 and $FUNC2"
fi

test_actual() { # Compares $TMPDIR/expected with set_ftrace_filter
    cat set_ftrace_filter | grep -v '#' | cut -d' ' -f1 | cut -d':' -f1 | sort -u > $TMPDIR/actual
    DIFF=`diff $TMPDIR/actual $TMPDIR/expected`
    test -z "$DIFF"
}

# Set traceoff trigger for all fuctions with "lock" in their name
cat available_filter_functions | cut -d' ' -f1 |  grep 'lock' | sort -u > $TMPDIR/expected
echo '*lock*:traceoff' > set_ftrace_filter
test_actual

# now remove all with 'try' in it, and end with lock
grep -v 'try.*lock$' $TMPDIR/expected > $TMPDIR/expected2
mv $TMPDIR/expected2 $TMPDIR/expected
echo '!*try*lock:traceoff' >> set_ftrace_filter
test_actual

# remove all that start with "m" and end with "lock"
grep -v '^m.*lock$' $TMPDIR/expected > $TMPDIR/expected2
mv $TMPDIR/expected2 $TMPDIR/expected
echo '!m*lock:traceoff' >> set_ftrace_filter
test_actual

# remove all that start with "c" and have "unlock"
grep -v '^c.*unlock' $TMPDIR/expected > $TMPDIR/expected2
mv $TMPDIR/expected2 $TMPDIR/expected
echo '!c*unlock*:traceoff' >> set_ftrace_filter
test_actual

# clear all the rest
> $TMPDIR/expected
echo '!*:traceoff' >> set_ftrace_filter
test_actual

rm $TMPDIR/expected
rm $TMPDIR/actual

exit 0
