#!/bin/sh
set -eu

SYSFS_DIR="/sys/kernel/security/uos_exec_cache_refresh"
WORK_DIR="${TMPDIR:-/tmp}/uosecr-splice-test.$$"
HELPER="$WORK_DIR/splice_read"
SOURCE="$WORK_DIR/splice_read.c"
TEST_FILE="${1:-/etc/passwd}"

die()
{
	echo "verify-splice: $*" >&2
	exit 1
}

read_stat()
{
	key="$1"
	awk -v key="$key" '$1 == key { print $2 }' "$SYSFS_DIR/stats"
}

read_control()
{
	key="$1"
	cat "$SYSFS_DIR/$key"
}

write_control()
{
	key="$1"
	value="$2"
	printf '%s\n' "$value" > "$SYSFS_DIR/$key"
}

cleanup()
{
	if [ -n "${OLD_MODE:-}" ]; then
		write_control mode "$OLD_MODE" || true
	fi
	if [ -n "${OLD_SPLICE_AUDIT:-}" ]; then
		write_control splice_audit "$OLD_SPLICE_AUDIT" || true
	fi
	rm -rf "$WORK_DIR"
}

[ "$(id -u)" -eq 0 ] || die "run as root"
[ -d "$SYSFS_DIR" ] || die "$SYSFS_DIR not found; load uosecr first"
[ -r "$SYSFS_DIR/stats" ] || die "$SYSFS_DIR/stats is not readable"
[ -w "$SYSFS_DIR/mode" ] || die "$SYSFS_DIR/mode is not writable"
[ -w "$SYSFS_DIR/splice_audit" ] || die "$SYSFS_DIR/splice_audit is not writable"
[ -f "$TEST_FILE" ] || die "$TEST_FILE is not a regular file"
[ -r "$TEST_FILE" ] || die "$TEST_FILE is not readable"
[ "$(stat -c '%u' "$TEST_FILE")" = "0" ] || die "$TEST_FILE is not root-owned"

CC="${CC:-cc}"
command -v "$CC" >/dev/null 2>&1 || CC=gcc
command -v "$CC" >/dev/null 2>&1 || die "cc/gcc not found"

mkdir -p "$WORK_DIR"
trap cleanup EXIT INT TERM

OLD_MODE="$(read_control mode)"
OLD_SPLICE_AUDIT="$(read_control splice_audit)"
write_control mode 1
write_control splice_audit 1

cat > "$SOURCE" <<'EOF'
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char **argv)
{
	char buf[4096];
	loff_t off = 0;
	ssize_t n;
	int fd;
	int pipefd[2];

	if (argc != 2) {
		fprintf(stderr, "usage: %s <file>\n", argv[0]);
		return 2;
	}

	fd = open(argv[1], O_RDONLY);
	if (fd < 0) {
		fprintf(stderr, "open: %s\n", strerror(errno));
		return 1;
	}

	if (pipe(pipefd) < 0) {
		fprintf(stderr, "pipe: %s\n", strerror(errno));
		return 1;
	}

	n = splice(fd, &off, pipefd[1], NULL, sizeof(buf), 0);
	if (n < 0) {
		fprintf(stderr, "splice: %s\n", strerror(errno));
		return 1;
	}

	while (n > 0) {
		ssize_t r = read(pipefd[0], buf, n > (ssize_t)sizeof(buf) ?
				 (ssize_t)sizeof(buf) : n);
		if (r <= 0) {
			fprintf(stderr, "read pipe: %s\n",
				r < 0 ? strerror(errno) : "short read");
			return 1;
		}
		n -= r;
	}

	close(pipefd[0]);
	close(pipefd[1]);
	close(fd);
	return 0;
}
EOF

"$CC" -O2 -Wall -Wextra -o "$HELPER" "$SOURCE"

before_checked="$(read_stat splice_checked)"
before_refreshed="$(read_stat splice_refreshed)"

"$HELPER" "$TEST_FILE"

after_checked="$(read_stat splice_checked)"
after_refreshed="$(read_stat splice_refreshed)"

echo "splice_checked: $before_checked -> $after_checked"
echo "splice_refreshed: $before_refreshed -> $after_refreshed"

if [ "$after_checked" -gt "$before_checked" ] &&
   [ "$after_refreshed" -gt "$before_refreshed" ]; then
	echo "PASS: uosecr splice hook was triggered"
	exit 0
fi

echo "FAIL: splice counters did not increase" >&2
echo "Check dmesg for uosecr messages and try a root-owned file on a disk filesystem." >&2
exit 1
