#!/bin/sh
# extract.sh -- machine-extract the PRODUCTION pccard CIS parser, byte-identical,
# from the guest's own /usr/src kernel tree, into an include-able .inc for the
# userland verification rig.
#
# The extraction is sha256-gated: the four pccard source files must match the
# pristine audit-tree hashes (printed as PRISTINE_HASH lines). If a file was
# patched (fix-validation phase), the manifest records PATCHED and --allow-patched
# is required.
#
# Usage: sh extract.sh <outdir> [--allow-patched]
set -eu

OUT="${1:-.}"
ALLOW_PATCHED="${2:-}"
SRC=/usr/src/sys/bus/pccard

# Pristine sha256 of the audit tree (sys/bus/pccard/* as audited).
P_CIS_C=acdd2484925fd5f09ab7266fcbb575134ae73e72c20f3e844c236ef0c2c2304c
P_VAR_H=3e73a8771c78e6aa9e52c764f1431571b835674ec87aecb4d32575c6dcdb4141
P_CISH=9ed5d42411f363810ead8c9a6fd7e67abda1700504342325bb03fc281c8e0959
P_REG_H=55e55e8a7be4784ed1400c9de2c7dd72455e08b053dda985cb43e2fe2eb80309
P_QUEUE=6072482fad8732b5ea0f315ed0fc0acd7abd02c3f8180c0733ea1b8c671d0745

h() { sha256 -r "$1" | awk '{print $1}'; }

mkdir -p "$OUT"
MAN="$OUT/extract_manifest.txt"
{
	echo "=== verbatim extraction manifest ==="
	date
	uname -a
} > "$MAN"

STATE=PRISTINE
check() { # name file pristhash
	got=$(h "$2")
	if [ "$got" = "$3" ]; then
		echo "VERBATIM_CHECK $1 PRISTINE $got" | tee -a "$MAN"
	else
		echo "VERBATIM_CHECK $1 PATCHED  $got (pristine=$3)" | tee -a "$MAN"
		STATE=PATCHED
	fi
}

check pccard_cis.c  "$SRC/pccard_cis.c"  "$P_CIS_C"
check pccardvar.h   "$SRC/pccardvar.h"   "$P_VAR_H"
check pccard_cis.h  "$SRC/pccard_cis.h"  "$P_CISH"
check pccardreg.h   "$SRC/pccardreg.h"   "$P_REG_H"
check queue.h       /usr/src/sys/sys/queue.h "$P_QUEUE"
check queue.h.usrinc /usr/include/sys/queue.h "$P_QUEUE"

if [ "$STATE" = PATCHED ] && [ "$ALLOW_PATCHED" != "--allow-patched" ]; then
	echo "REFUSING: source tree is PATCHED and --allow-patched not given" | tee -a "$MAN"
	exit 3
fi
echo "SOURCE_STATE=$STATE" | tee -a "$MAN"

# --- byte-identical extraction ---
# PRISTINE: fixed sed line-ranges from the audited layout (byte-identical).
# PATCHED : anchor-based ranges (fixes shift line numbers; anchors are the
#           same structural landmarks, extraction recorded in the manifest).
if [ "$STATE" = PRISTINE ]; then
	# pccard_cis.c:
	#   51-60    extern debug + PCCARDCISDEBUG DPRINTF/DEVPRINTF macros
	#   62-444   PCCARD_CIS_SIZE, struct cis_state, pccard_read_cis, pccard_scan_cis
	#   612-1294 pccard_parse_cis_tuple + decode_funce
	sed -n '51,444p;612,1294p' "$SRC/pccard_cis.c" > "$OUT/pccard_cis_core.inc"
else
	A1=$(grep -n '^extern int	pccard_cis_debug;' "$SRC/pccard_cis.c" | cut -d: -f1)
	A2=$(grep -n '^/\* XXX this is incredibly verbose' "$SRC/pccard_cis.c" | cut -d: -f1)
	B1=$(grep -n '^pccard_parse_cis_tuple(const struct pccard_tuple \*tuple, void \*arg)$' \
		"$SRC/pccard_cis.c" | cut -d: -f1)
	B1=$((B1 - 1))		# include preceding "static int"
	B2=$(wc -l < "$SRC/pccard_cis.c")
	sed -n "${A1},$((A2 - 2))p;${B1},${B2}p" "$SRC/pccard_cis.c" \
		> "$OUT/pccard_cis_core.inc"
	echo "anchor ranges: ${A1},$((A2 - 2)) and ${B1},${B2} (patched layout)" >> "$MAN"
fi

# pccardvar.h:
#   62-70    struct pccard_mem_handle (member of pccard_function)
#   74-112   CFE flags + struct pccard_config_entry
#   114-126  funce structs
#   128-160  struct pccard_function
#   165-184  struct pccard_card
#   196-203  struct pccard_softc
#   213-222  struct pccard_tuple + pccard_scan_t
#   250-253  prototypes
#   255-280  pccard_cis_read_1 / pccard_tuple_read_* macros
#   357-363  PCCARD_A_MEM_* flags
sed -n '62,70p;74,112p;114,126p;128,160p;165,184p;196,203p;213,222p;250,253p;255,280p;357,363p' \
	"$SRC/pccardvar.h" > "$OUT/pccardvar_rig.inc"

# constant headers copied whole (no #includes inside them -- verified)
cp "$SRC/pccard_cis.h"  "$OUT/pccard_cis.h"
cp "$SRC/pccardreg.h"   "$OUT/pccardreg.h"

{
	echo "--- artifacts ---"
	echo "ranges: pccard_cis.c 51,444p;612,1294p | pccardvar.h 62,70p;74,112p;114,126p;128,160p;165,184p;196,203p;213,222p;250,253p;255,280p;357,363p"
	sha256 -r "$OUT/pccard_cis_core.inc" "$OUT/pccardvar_rig.inc" "$OUT/pccard_cis.h" "$OUT/pccardreg.h"
	echo "bytes core=$(wc -c < "$OUT/pccard_cis_core.inc") var=$(wc -c < "$OUT/pccardvar_rig.inc")"
} >> "$MAN"

echo "EXTRACT_OK state=$STATE"
