#!/bin/bash
# Run GNU SMACK/ROOTFS tests in QEMU with SMACK-enabled kernel
# Usage: run-gnu-tests-smack-ci.sh [GNU_DIR] [OUTPUT_DIR]
# spell-checker:ignore commoncap rootfs zstd unzstd cpio newc nographic smackfs devtmpfs tmpfs poweroff libm libgcc libpthread libdl librt sysfs rwxat setuidgid
set -e

: ${PROFILE:=release-small}
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_DIR="$(dirname "$SCRIPT_DIR")"
GNU_DIR="${1:-$REPO_DIR/../gnu}"
OUTPUT_DIR="${2:-$REPO_DIR/target/qemu-test-results}"
QEMU_DIR="$REPO_DIR/target/qemu-test"

echo "Setting up SMACK/ROOTFS test environment..."
rm -rf "$QEMU_DIR"
mkdir -p "$QEMU_DIR"/{rootfs/{bin,lib64,proc,sys,dev,tmp,etc,gnu},kernel}

# Copy Ubuntu kernel (runner's kernel does not work)
sudo apt-get update || :
sudo apt-get install -y --no-install-recommends linux-image-generic
sudo install -Dvm644 "$(ls -1 /boot/vmlinuz-*-generic | head -n 1)" "$QEMU_DIR/kernel/vmlinuz"

# Setup busybox
curl -L -o b.tar.gz https://dl-cdn.alpinelinux.org/alpine/latest-stable/main/x86_64/busybox-static-1.37.0-r30.apk
tar -xf b.tar.gz
install -Dvm755 bin/busybox.static "$QEMU_DIR/rootfs/bin/busybox"
(cd "$QEMU_DIR/rootfs/bin" && ./busybox --list | xargs -I{} ln -sf busybox {} 2>/dev/null)

# Copy required libraries
for lib in ld-linux-x86-64.so.2 libc.so.6 libm.so.6 libgcc_s.so.1 libpthread.so.0 libdl.so.2 librt.so.1; do
    path=$(ldconfig -p | grep "$lib" | head -1 | awk '{print $NF}')
    [ -n "$path" ] && [ -f "$path" ] && cp -L "$path" "$QEMU_DIR/rootfs/lib64/" 2>/dev/null || true
done

# Create minimal config files
echo -e "root:x:0:0:root:/root:/bin/sh\nnobody:x:65534:65534:nobody:/nonexistent:/bin/sh" > "$QEMU_DIR/rootfs/etc/passwd"
echo -e "root:x:0:\nnobody:x:65534:" > "$QEMU_DIR/rootfs/etc/group"
touch "$QEMU_DIR/rootfs/etc/mtab"

# Copy GNU tests
cp -r "$GNU_DIR/tests" "$QEMU_DIR/rootfs/gnu/"

# Create init script
cat > "$QEMU_DIR/rootfs/init" << 'INIT'
#!/bin/sh
mount -t proc proc /proc
mount -t sysfs sys /sys
mount -t smackfs smackfs /sys/fs/smackfs 2>/dev/null || true
if [ -d /sys/fs/smackfs ]; then
    echo "_" > /proc/self/attr/current 2>/dev/null || true
    echo "_ _ rwxat" > /sys/fs/smackfs/load 2>/dev/null || true
fi
mount -t devtmpfs devtmpfs /dev 2>/dev/null || true
ln -sf /proc/mounts /etc/mtab
mkdir -p /tmp && mount -t tmpfs tmpfs /tmp
chmod 1777 /tmp
export PATH="/bin:$PATH" srcdir="/gnu" LD_LIBRARY_PATH="/lib64"
if [ -n "$RUN_AS_USER" ]; then
    # Run in /tmp so non-root user can create temp directories
    cd /tmp
    setuidgid "$RUN_AS_USER" sh "/gnu/tests/$TEST_SCRIPT"
else
    cd /gnu/tests
    sh "$TEST_SCRIPT"
fi
echo "EXIT:$?"
poweroff -f
INIT
chmod +x "$QEMU_DIR/rootfs/init"

# Build utilities for SMACK/ROOTFS tests
echo "Building utilities for SMACK/ROOTFS tests..."
cargo build --profile="${PROFILE}" --features=feat_smack,id,ls,mkdir,mkfifo,mknod,df --no-default-features

# Find SMACK tests and tests requiring rootfs in mtab (only available in QEMU environment)
QEMU_TESTS=$(grep -l -E 'require_smack_|rootfs in mtab' -r "$GNU_DIR/tests/" 2>/dev/null | sort -u || true)
[ -z "$QEMU_TESTS" ] && { echo "No SMACK/ROOTFS tests found"; exit 0; }

echo "Found $(echo "$QEMU_TESTS" | wc -l) SMACK/ROOTFS tests"

# Create output directory
rm -rf "$OUTPUT_DIR"
mkdir -p "$OUTPUT_DIR"

# Run each test
for TEST_PATH in $QEMU_TESTS; do
    TEST_REL="${TEST_PATH#"$GNU_DIR"/tests/}"
    TEST_DIR=$(dirname "$TEST_REL")
    TEST_NAME=$(basename "$TEST_REL" .sh)

    echo "Running: $TEST_REL"

    # Determine if test needs non-root user
    RUN_AS_USER=""
    if echo "$TEST_REL" | grep -q "no-root"; then
        RUN_AS_USER="nobody"
    fi

    # Create working copy
    WORK="/tmp/qemu-test-$$"
    rm -rf "$WORK" "$WORK.gz"
    cp -a "$QEMU_DIR/rootfs" "$WORK"

    # Hardlink utilities for SMACK/ROOTFS tests
    for U in $("$REPO_DIR/target/${PROFILE}/coreutils" --list); do
        ln -f "$REPO_DIR/target/${PROFILE}/coreutils" "$WORK/bin/$U"
    done

    # Set test script path and user
    sed -i "s|\$TEST_SCRIPT|$TEST_REL|g" "$WORK/init"
    if [ -n "$RUN_AS_USER" ]; then
        sed -i "s|\$RUN_AS_USER|$RUN_AS_USER|g" "$WORK/init"
    else
        sed -i "s|\$RUN_AS_USER||g" "$WORK/init"
    fi

    # Build initramfs and run
    (cd "$WORK" && find . | cpio -o -H newc 2>/dev/null | gzip > "$WORK.gz")

    OUTPUT=$(timeout 120 qemu-system-x86_64 \
        -kernel "$QEMU_DIR/kernel/vmlinuz" \
        -initrd "$WORK.gz" \
        -append "console=ttyS0 quiet panic=-1 lsm=capability,smack,commoncap security=smack apparmor=0" \
        -nographic -m 256M -no-reboot 2>&1) || true

    # Determine result
    if echo "$OUTPUT" | grep -q "EXIT:0"; then
        RESULT="PASS"; EXIT_STATUS=0
    elif echo "$OUTPUT" | grep -q "EXIT:77"; then
        RESULT="SKIP"; EXIT_STATUS=77
    else
        RESULT="FAIL"; EXIT_STATUS=1
    fi

    echo "  $RESULT: $TEST_REL"

    # Create log file for gnu-json-result.py
    mkdir -p "$OUTPUT_DIR/$TEST_DIR"
    echo "$OUTPUT" > "$OUTPUT_DIR/$TEST_DIR/$TEST_NAME.log"
    echo "" >> "$OUTPUT_DIR/$TEST_DIR/$TEST_NAME.log"
    echo "$RESULT $TEST_NAME.sh (exit status: $EXIT_STATUS)" >> "$OUTPUT_DIR/$TEST_DIR/$TEST_NAME.log"

    rm -rf "$WORK" "$WORK.gz"
done

echo "Done. Results in $OUTPUT_DIR"
