#!/bin/bash

# connection parameters
ip=127.0.0.1
port=10022
path=/usr/local
monitor=mysocket

ssh="ssh -i ~/.ssh/qemukey -p $port root@$ip"
scp="scp -i ~/.ssh/qemukey -P $port root@$ip"

# variables affected by options
FILEEDITOR=nano
FILENAME=big-file.txt
FILESIZE=134217728 # 128 MiB
BLOCKSIZE=4096     # 4 KiB

# display help function
display_help() {
    echo "Usage: $0 [option...] " >&2
    echo
    echo "   -b, --blocksize            Set the block size used for dd in bytes (default: 4096)"
    echo "   -f, --file                 Set the name of the file to be edited (default: big-file.txt)"
    echo "   -s, --filesize             File size in MiB (default: 128)"
    echo "   -e, --editor               Set the editor used for the test (default: nano)"
    echo "   -h, --help                 Display help message"
    echo
}

while true; do
    # if [ $# -eq 0 ];then
    # 	echo $#
    # 	break
    # fi
    case "$1" in
        -h | --help)
            display_help
            exit 0
            ;;
        -b | --blocksize)
	    BLOCKSIZE=$2
            shift 2
            ;;
        -f | --file)
	    FILENAME=$2
            shift 2
            ;;
        -s | --size)
	    FILESIZE=$(($2 * 1048576))
            shift 2
            ;;
        -e | --editor)
	    FILEEDITOR=$2
            shift 2
            ;;
        -*)
            echo "Error: Unknown option: $1" >&2
            exit 1
            ;;
        *)  # No more options
            break
            ;;
    esac
done

# test case parameters
filechunks=$(($FILESIZE / $BLOCKSIZE))

tranq_secs=32
noisedir=foo
noisefilesize=256

do_panic() {
  echo "=> panic."
  # XXX: ssh will not wait(?) with an invalid connect timeout
  $ssh 'echo c > /proc/sysrq-trigger' &
}

do_reset() {
  echo "=> system_reset."
  echo "system_reset" | socat - unix-connect:$monitor
}

do_reboot() {
  echo "=> reboot."
  $ssh 'reboot'
  sleep 2
}

do_wait() {
  try=3
  while [ $try -gt 0 ]; do
    echo "Connecting ($try)..."
    if $ssh -o ConnectTimeout=5 "echo OK!"; then
      echo "Connected ok..."
      return 0
    fi
    try=$((try - 1))
  done
  echo "Connection error..."
  return 1
}

# Sync, and drop caches
do_sync() {
    echo "=> sync"
    $ssh "sync; sleep 2; sync; echo 3 > /proc/sys/vm/drop_caches"
}

do_detect() {
    echo "Scanning file..."
    size=$($ssh "du -b ${path}/${FILENAME}" | awk '{ print $1 }')
    if [[ $size != $FILESIZE ]]; then
	echo "Error triggered"
	exit 0
    fi
}

# Make sure that the monitor is running...
if ! echo "info status" | socat - unix-connect:$monitor > /dev/null 2>&1; then
    echo "QEMU not running"
    exit 0
fi

# Sanity check -- the specified editor should exist
if [[ $($ssh "export TERM=xterm; ${FILEEDITOR} --help > /dev/null 2>&1") -eq 127 ]] ; then
    echo "Editor \"${FILEEDITOR}\" does not exist on remote system"
    exit 127
fi

## local function to be run remotely so that we don't have latency
create_noise() {
    if [[ $# -ne 3 ]]; then
	echo "Wrong number of arguments for remote call"
	exit 1
    fi

    path=$1
    noisedir=$2
    noisefilesize=$3
    while true; do
	rm -rf ${path}/${noisedir}
	mkdir ${path}/${noisedir}
	for i in `seq 1 10000`; do
    	    dd if=/dev/zero of=${path}/${noisedir}/${i}.txt bs=${noisefilesize} count=1 conv=fsync > /dev/null 2>&1
	done
    done
}

while true; do

    echo "Looping..."

    do_wait || continue

    # Remove files from previous runs
    $ssh "rm ${path}/${FILENAME}* ${path}/.${FILENAME}.swp ${path}/.\#${FILENAME}* > /dev/null 2>&1"
    $ssh "rm -rf ${path}/${noisedir} > /dev/null 2>&1"
    do_sync

    # create a big file
    $ssh "dd if=/dev/zero of=${path}/${FILENAME} bs=${BLOCKSIZE} count=${filechunks} > /dev/null 2>&1"
    do_sync

    # create async noise
    echo "=> noise: will start I/O in ${tranq_secs} seconds..."
    sleep 2
    $ssh "$(typeset -f create_noise); sleep ${tranq_secs}; create_noise ${path} ${noisedir} ${noisefilesize}" &

    # fire up editor and trigger panic after editor returns (inline to avoid ssh latency)
    $ssh -t -x "export TERM=xterm; ${FILEEDITOR} ${path}/${FILENAME}; echo c > /proc/sysrq-trigger"

    # kill everything and reset
    # do_panic
    do_reset; sleep 2

    # check for errors; rinse and repeat
    do_wait || continue
    do_detect
done
