#!/bin/sh

set -ex

export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

mount -t proc none /proc
mount -t sysfs none /sys
mount -t debugfs debugfs /sys/kernel/debug/ || true
mount -t tracefs tracefs /sys/kernel/tracing/ || true
mount -t tmpfs none /mnt
mount -t tmpfs none /root
mount -t tmpfs none /run
mount -t tmpfs none /tmp

# create /dev/shm for faketime
mkdir /dev/shm
mount -t tmpfs none /dev/shm

# create overlay for /etc
mkdir /tmp/etc-overlay /tmp/etc-work
mount -t overlay overlay -o lowerdir=/etc,upperdir=/tmp/etc-overlay,workdir=/tmp/etc-work /etc

# switch to rauc dir
cd "$(dirname "$0")"

BUILD_DIR="$(realpath build)/"

# parse cmdline
for x in $(cat /proc/cmdline); do
  if [ "$x" = "shell" ]; then
    SHELL=1
    export MESON_BUILD_DIR=$BUILD_DIR
  elif [ "$x" = "system" ]; then
    SHELL=1
    SERVICE=1
  elif [ "$x" = "asan" ]; then
    export G_SLICE=always-malloc G_DEBUG=gc-friendly
    export ASAN_OPTIONS=malloc_context_size=64:fast_unwind_on_malloc=0
    export LSAN_OPTIONS=suppressions="$(pwd)/test/asan.supp"
    export UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1
  elif [ "$x" = "service-backtrace" ]; then
    SERVICE_BACKTRACE=1
  fi
done
if [ -n "$test" ]; then
  MESON_TEST="$test"
fi

hostname qemu-test

# loopback interface
ip addr add 127.0.0.1 dev lo
ip link set lo up

# main interface
ip link set eth0 up
ip addr add 10.0.2.15/24 dev eth0
ip link set eth0 up
ip route add default via 10.0.2.2

# remove potential symlink and set new qemu nameserver
rm -f /etc/resolv.conf
echo "nameserver 10.0.2.3" > /etc/resolv.conf

export HOME="/root"

# allow git access to our repo
git config --system --add safe.directory "$(pwd)"

# try to store coverage in tmpfs with acls to avoid issues with the
# unprivileged nbd helper
if type setfacl; then
  mkdir /tmp/cov
  setfacl -m d:u::rwx /tmp/cov
  setfacl -m d:g::rwx /tmp/cov
  setfacl -m d:o::rwx /tmp/cov
  export GCOV_PREFIX=/tmp/cov
fi

mkdir /tmp/bin
export PATH=/tmp/bin:$PATH

# create helper scripts to manage coverage data
if [ -n "$GCOV_PREFIX" ]; then
  cat > /tmp/bin/save_gcov_data <<EOF
#!/bin/sh
set -ex
cp -r -T "$GCOV_PREFIX$BUILD_DIR" "$BUILD_DIR" || true
EOF
  cat > /tmp/bin/clear_gcov_data <<EOF
#!/bin/sh
set -ex
  rm -rf "$GCOV_PREFIX$BUILD_DIR" || true
EOF
  chmod +x /tmp/bin/save_gcov_data /tmp/bin/clear_gcov_data
fi

# enable gdb history
cat > /root/.gdbinit <<EOF
set history filename $(pwd)/.qemu_gdb_history
set history save on
set print pretty on
EOF

# fake entropy
$BUILD_DIR/test/fakerand

# rauc binary in PATH
if [ -n "$SHELL" ]; then
  cp -a $BUILD_DIR/rauc /tmp/bin/rauc
fi
export RAUC_TEST_NBD_SERVER="$BUILD_DIR/rauc"

if type losetup; then
  truncate --size=64M /tmp/rauc-disk.img
  losetup -P /dev/loop0 /tmp/rauc-disk.img
  export RAUC_TEST_BLOCK_LOOP=/dev/loop0
fi

cat /proc/mtd

if [ -c /dev/mtd0 ] && type flashcp; then
  export RAUC_TEST_MTD_NOR=/dev/mtd0
fi

if [ -c /dev/mtd2 ] && type flash_erase; then
  export RAUC_TEST_MTD_NAND=/dev/mtd2
fi

if [ -c /dev/mtd3 ] && type ubiattach; then
  ubiattach -m 3 -d 0
  ubimkvol /dev/ubi0 -s 12096KiB -N rauc-test
  export RAUC_TEST_MTD_UBI=/dev/ubi0
  export RAUC_TEST_MTD_UBIVOL=/dev/ubi0_0
fi

if [ -b /dev/mmcblk0 ] && type mmc; then
  export RAUC_TEST_EMMC=/dev/mmcblk0
fi

if type casync; then
  export RAUC_TEST_CASYNC=1
fi

# remove potential host rauc system config
rm -rf /etc/rauc

# setup required for interactive system
if [ -n "$SERVICE" ]; then

  # create rauc system config for testing and data directory
  mkdir /etc/rauc
  cp qemu-test-rauc-config /etc/rauc/system.conf
  cp test/openssl-ca/dev-ca.pem /etc/rauc/ca.cert.pem

  # grub env
  mkdir -p /tmp/boot/grub
  mount --bind /tmp/boot /boot
  grub-editenv /tmp/boot/grub/grubenv set ORDER="A B" A_TRY="0" B_TRY="0" A_OK="1" B_OK="1"

  # fake slot devices
  truncate --size=64M /tmp/rootdev
  mkfs.ext4 /tmp/rootdev
  truncate --size=64M /tmp/appdev
  mkfs.ext4 /tmp/appdev

  # fake artifact repos
  mkdir /tmp/file-artifacts-single
  touch /tmp/file-artifacts-single/.artifact-empty-e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
  ln -s .artifact-empty-e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 /tmp/file-artifacts-single/empty
  mkdir /tmp/file-artifacts-dual /tmp/file-artifacts-dual/rootfs.0 /tmp/file-artifacts-dual/rootfs.1
  touch /tmp/file-artifacts-dual/.artifact-empty-e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
  ln -s ../.artifact-empty-e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 /tmp/file-artifacts-dual/rootfs.0/empty
  mkdir /tmp/tree-artifacts

  # rauc and dbus service start
  if grep -q "ENABLE_SERVICE 1" $BUILD_DIR/config.h; then
    # dbus
    cp -a $BUILD_DIR/data/de.pengutronix.rauc.conf /etc/dbus-1/system.d
    chown root:root /etc/dbus-1/system.d/de.pengutronix.rauc.conf
    chmod 644 /etc/dbus-1/system.d/de.pengutronix.rauc.conf
    mount -t tmpfs none /var/run
    mkdir -p /var/run/dbus
    time dbus-daemon --system --fork --nopidfile --nosyslog --print-address

    # rauc
    if [ -n "$SERVICE_BACKTRACE" ] && type gdb; then
      gdb --batch --ex "run" --ex "thread apply all bt" --args rauc service &
    else
      rauc service &
    fi
  fi
fi

if type nginx; then
  mount -t tmpfs tmpfs /var/lib/nginx
  mount -t tmpfs tmpfs /var/log/nginx
  nginx -c test/nginx.conf -p "$PWD"
  export RAUC_TEST_HTTP_SERVER=1
fi

if python3 test/nginx_backend.py; then
  export RAUC_TEST_HTTP_BACKEND=1
fi

echo "use ctrl-a x to exit and ctrl-a c to access the qemu monitor"

echo "system ready"

if [ -n "$SHELL" ]; then
  echo "alias ll='ls -l'" >> /tmp/bashrc
  BASH_CMD="exec bash --rcfile /tmp/bashrc"
  if type resize; then
    BASH_CMD="eval \$(resize); $BASH_CMD"
  fi
  HISTFILE="$(pwd)/.qemu_bash_history" \
  setsid bash -c "$BASH_CMD" </dev/ttyS0 >/dev/ttyS0 2>&1 || echo exit-code=$?
  save_gcov_data
  echo o > /proc/sysrq-trigger
fi

if [ -n "$SERVICE" ]; then
  rauc status mark-good
fi

if meson test -C $BUILD_DIR "$MESON_TEST" -v; then
  touch qemu-test-ok
  echo "RESULT: PASSED"
else
  cat $BUILD_DIR/meson-logs/testlog.txt || true
  # show system status on error
  mount || true
  df -h || true
  free || true
  echo "RESULT: FAILED"
fi
save_gcov_data
sleep 1
echo o > /proc/sysrq-trigger
sleep 1
