#!/bin/sh

. $LKP_SRC/lib/env.sh
. $LKP_SRC/lib/wait.sh
. $LKP_SRC/lib/upload.sh
. $LKP_SRC/lib/kmemleak.sh

umask 002

any_pid_alive()
{
	local pidfile=$1
	local ps_out
	local pid

	# busybox ps does not accept any parameter
	ps_out=$(ps axho pid 2>/dev/null)

	if [ -n "$ps_out" ]; then
		echo "$ps_out" | grep -qFwf $pidfile
	else
		is_busybox_ps=1
		for pid in $(cat $pidfile)
		do
			test -d /proc/$pid && return
		done
		return 1
	fi
}

wait_for_bg_procs()
{
	local pidfile="$TMP/.pid-wait-bg-procs"
	[ -s "$pidfile" ] || return 0

	echo wait for background processes: $(cat $pidfile $TMP/.name-wait-bg-procs)

	for i in 1 2 3 4 5
	do
		sleep $i
		any_pid_alive $pidfile && continue
		return $i
	done

	echo "some processes do not quit in time" >&2
	if [ -n "$is_busybox_ps" ]; then
		ps
	else
		ps axho pid | grep -Fxf $pidfile | xargs ps u
		ps faux
	fi > $TMP_RESULT_ROOT/bg-procs-debug

	return $i
}

kill_bg_procs()
{
	local signal=$1
	local wait_pidfile="$TMP/.pid-wait-bg-procs"
	local pids
	local pid

	for pidfile in $TMP/pid-bg-proc-*
	do
		[ -s "$pidfile" ] || continue

		if [ -s "$wait_pidfile" ]; then
			pids=$(grep -v -x -F -f "$wait_pidfile" "$pidfile")
		else
			pids=$(cat "$pidfile")
		fi

		[ -n "$pids" ] || continue

		for pid in $pids
		do
			[ -d /proc/$pid ] || continue
			explain_kill $pid
			/bin/kill $signal $pid ||
			echo "failed to kill background process	${pidfile##*/pid-bg-proc--}" >&2
		done
	done
}

# There are 2 kind of background process termination mechanisms:
# 1) some smart monitors/daemons run setup_wait() and wait for the below post-test event
#    => $TMP/.pid-wait-bg-proc
$LKP_SRC/bin/event/wakeup activate-monitor
$LKP_SRC/bin/event/wakeup post-test
touch $TMP/post-run
sleep 1
# 2) most simple background processes run until being killed
#    => $TMP/pid-bg-proc-*
kill_bg_procs -TERM

wait_for_bg_procs
sleep 1
kill_bg_procs -KILL

for post_run in $TMP_RESULT_ROOT/post-run.* $LKP_SRC/post-run/*; do
	[ -f "$post_run" ] && sh "$post_run"
done

has_advance_pgrep()
{
	has_cmd pgrep && pgrep -h 2>/dev/null | grep -qw -- --pidfile
}

wait_for_pipe()
{
	local i
	local result

	# If setup scripts failed, monitors&tests won't run and .pid-pipes
	# will be missing.
	[ -e $TMP/.pid-pipes ] || return

	for i in $(seq 5)
	do
		sleep $i
		if has_advance_pgrep; then
			pgrep --pidfile $TMP/.pid-pipes 'tee|cat|gzip' >/dev/null && continue
		else
			any_pid_alive $TMP/.pid-pipes && continue
		fi
		break
	done

	for i in $(seq 5)
	do
		sleep $i

		for result in ${tmp_results}
		do
			[ "${result%.gz}" != "$result" ] || continue
			[ -s "$result" ] && continue

			echo "wait_for_pipe $i: empty $result"
			continue 2
		done

		return 0
	done

	echo "wait_for_pipe timeout $i" >&2

	# Throw out stderr when monitors did not start due to waiting on activate-monitor
	has_cmd pgrep &&
	pgrep -f "$LKP_SRC/bin/event/wait activate-monitor" >/dev/null &&
		echo "some monitors are blocked by activate-monitor" >&2

	ps faux 2>/dev/null > $RESULT_ROOT/pipe-debug || ps > $RESULT_ROOT/pipe-debug
	ls -l $TMP_RESULT_ROOT
	return 1
}

# program log (such as sleep in boot job) will be uploaded by this function
copy_results()
{
	[ -n "$TMP_RESULT_ROOT" ] || return
	[ "$result_fs" != "raw_upload" ] && [ "$TMP_RESULT_ROOT" = "$RESULT_ROOT" ] && return

	local tmp_results="$(find $TMP_RESULT_ROOT -type f -size +0)"
	[ -n "$tmp_results" ] || return

	# give chance to monitor fifo writer to sync data back to file
	wait_for_pipe

	upload_files $tmp_results
}

copy_time_files()
{
	local ret_copy_time_files=0

	for time_file in $TMP/*.time
	do
		[ -e "$time_file" ] || return

		if upload_files $time_file; then
			cat $time_file >> $TMP/time
		else
			ret_copy_time_files=1
		fi
	done

	[ -s $TMP/time ] && upload_files $TMP/time || return

	return $ret_copy_time_files
}

copy_time_files || ps faux --cols 1000 2>/dev/null > $RESULT_ROOT/time-debug || ps > $RESULT_ROOT/time-debug

copy_results

[ "$kconfig" = "x86_64-rhel-8.3-gcov" -o "$kconfig" = "x86_64-rhel-7.6-gcov" -o "$kconfig" = "x86_64-rhel-7.2-gcov" ] && [ -d /sys/kernel/debug/gcov ] && {
	$LKP_SRC/tools/gather-gcov-test $TMP/gcov-test.tar.gz
	upload_files $TMP/gcov-test.tar.gz
}

kmemleak_is_enabled && {
	cat /sys/kernel/debug/kmemleak >/tmp/debug-kmemleak
	upload_files /tmp/debug-kmemleak
}

# the busybox reduced dmesg/truncate will refuse to run and it's not a big deal
dmesg --facility user --human --decode --color=always > $TMP/umesg 2>/dev/null
truncate --no-create --size='<10M' $TMP/output $TMP/stdout $TMP/stderr $TMP/umesg 2>/dev/null

upload_files	$TMP/boot-time	\
		$TMP/stdout	\
		$TMP/stderr	\
		$TMP/output	\
		$TMP/umesg

[ -s $TMP/env.yaml ] &&
upload_files	$TMP/env.yaml

[ -s $TMP/program_list ] &&
upload_files	$TMP/program_list

upload_qemu_results()
{
	# result_root: /root/.lkp//result/kvm:stream/100%-10000000-true-performance/lkp-skl-4sp1/debian-x86_64-20180403.cgz/x86_64-rhel-7.2/gcc-7/84df9525b0c27f3ebc2ebb1864fa62a97fdedb7d/x86_64-softmmu/d3c2bbb166f8cd840a3f4efec31d55485f1360ed/84df9525b0c27f3ebc2ebb1864fa62a97fdedb7d/0
	local guest_rt=$(grep 'result_root: ' $TMP/stdout | awk -F'result_root: ' '{print $2}')
	[ -f "$guest_rt/output" ] || return
	upload_files -t guest_result $guest_rt

	mkdir -p /tmp/host_rt
	# backup host log to host_rt
	cp -arf $TMP_RESULT_ROOT/* /tmp/host_rt
	[ "$RESULT_ROOT" = "$TMP_RESULT_ROOT" ] || cp -arf $RESULT_ROOT/* /tmp/host_rt
	upload_files -t host_result /tmp/host_rt/*
	upload_files $guest_rt/*  # override the origin results
}

need_run_on_vmm && upload_qemu_results

exit 0
