#!/bin/bash

# Check kGraft patching status
# Libor Pechacek <lpechacek@suse.com>

unset VERBOSE

function kgr_in_progress() {
    [ "$(cat /sys/kernel/kgraft/in_progress)" -ne 0 ]
}

function kgr_poke_processes() {
    for PROC in /proc/[0-9]*; do
	if [ "$(cat $PROC/kgr_in_progress)" -ne 0 ]; then
	    PID=$(echo $PROC | cut -d/ -f3)
	    if [ -n "$VERBOSE" ]; then
		echo "sending $PID STOP/CONT"
	    fi
	    kill -STOP $PID
	    kill -CONT $PID
	fi
    done
}

function kgr_dump_blocking_processes() {
    unset PIDS

    for PROC in /proc/[0-9]*; do
	if [ "$(cat $PROC/kgr_in_progress)" -ne 0 ]; then
	    DIR=${PROC%/kgr_in_progress}
	    PID=${DIR#/proc/}
	    if [ -n "$VERBOSE" ]; then
		COMM="$(cat $DIR/cmdline | tr \0 \ )"
		# fallback to the command name, for example for kernel threads
		[ -z "$COMM" ] && COMM="[$(cat $DIR/comm | tr \0 \ )]"
		echo "$PID $COMM"
		if [ ${VERBOSE:-0} -gt 1 ]; then
		    cat $DIR/stack | sed 's/^/  /'
		fi
	    else
		echo $PID
	    fi
	    PIDS="$PIDS $PID"
	fi
    done
    if [ -z "$PIDS" -a -n "$VERBOSE" ]; then
	echo "no processes with kgr_in_progress set"
    fi
}

function kgr_status() {
    if kgr_in_progress ; then
	echo "in_progress"
    else
	echo "ready"
    fi
}

function kgr_patches() {
    unset PATCHES_FOUND
    for d in /sys/kernel/kgraft/*; do
	[ ! -d "$d" ] && continue
	PATCH_NAME=${d#/sys/kernel/kgraft/}
	PATCH_MOD=$(readlink $d/owner)
	PATCH_MOD=${PATCH_MOD#../../../module/}
	echo -n "${PATCH_MOD}"
	if [ -n "$VERBOSE" ]; then
	    echo " ($PATCH_NAME)"
	else
	    echo
	fi
	PATCHES_FOUND=1
    done
    if [ -z "$PATCHES_FOUND" -a -n "$VERBOSE" ]; then
	echo "no patch"
    fi
}

USAGE="Usage: $0 [-h][-v] COMMAND
Query and manipulate kGraft patching status.

Commands:
	status:    display the overall status of kGraft patching
	patches:   display the list of loaded patches
	blocking:  list processes that are preventing kGraft patching
		   from finishing
	poke:      move forward with the kGraft patching by sending
		   STOP and CONT signal to the pending processes

Options:
	-h	   print this help
	-v	   more detailed output

Report bugs at https://bugzilla.suse.com/."
PKGVERSION="@@VERSION@@"

while getopts vh-: opt
do
    case $opt$OPTARG in
    -help|h)
	exec echo "$USAGE" ;;
    -version)
	exec echo "kgr $PKGVERSION" ;;
    v) VERBOSE=$((${VERBOSE:-0} + 1)) ;;
    *)
	echo "$0: try '$0 --help'" >&2; exit 1 ;;
    esac
done

shift `expr $OPTIND - 1`

if [ $# -ne 1 ]; then
    echo "Error: unknown command, try --help" >&2
    exit 1
fi

case $1 in
    blocking) kgr_dump_blocking_processes ;;
    poke) kgr_poke_processes ;;
    status) kgr_status ;;
    patches) kgr_patches ;;
    *) echo "unknown command \`$1'"
esac
