#!/bin/bash
#
# platform-identity-audit.sh — Find runtime references to legacy platform
# identity strings (i86pc, i386) that would break when the kernel reports
# "amd64" for uname -m, uname -p, and uname -i.
#
# Usage: ./platform-identity-audit.sh [src_root]
#        Default src_root: directory containing this script's ../../..
#
# What changed:
#   uname -m / SI_MACHINE:       "i86pc" -> "amd64"
#   uname -p / SI_ARCHITECTURE:  "i386"  -> "amd64"
#   uname -i / SI_PLATFORM:      "i86pc" -> "amd64"
#
# What did NOT change:
#   SI_ARCHITECTURE_32:  still "i386"
#   SI_ARCHITECTURE_64:  still "amd64"
#   SI_ARCHITECTURE_K:   still "amd64"
#   Build-time MACH=i386, PLATFORM=i86pc (directory names)
#

set -o pipefail

SRCROOT="${1:-$(cd "$(dirname "$0")/../../.." && pwd)}"
USR_SRC="$SRCROOT/usr/src"

if [ ! -d "$USR_SRC/cmd" ] || [ ! -d "$USR_SRC/lib" ]; then
    echo "ERROR: Cannot find usr/src/{cmd,lib} under $SRCROOT" >&2
    exit 1
fi

RED='\033[0;31m'
YEL='\033[0;33m'
GRN='\033[0;32m'
CYN='\033[0;36m'
NC='\033[0m'

results=$(mktemp)
trap "rm -f $results" EXIT

echo "================================================================"
echo "Platform Identity Audit — $(date)"
echo "Source root: $SRCROOT"
echo "================================================================"
echo ""

classify() {
    local file="$1" lineno="$2" content="$3" category="$4"
    local ctx_start=$((lineno > 4 ? lineno - 4 : 1))
    local ctx_end=$((lineno + 4))
    local context
    context=$(sed -n "${ctx_start},${ctx_end}p" "$file" 2>/dev/null)

    # Already handles amd64?
    if echo "$context" | grep -q '"amd64"\|amd64' 2>/dev/null; then
        echo -e "  ${GRN}[FIXED]${NC} ${file#$USR_SRC/}:$lineno"
        echo "FIXED" >> "$results"
        return
    fi

    # Safe: SI_ARCHITECTURE_32/64 context (unchanged syscalls)
    local broad_start=$((lineno > 15 ? lineno - 15 : 1))
    local broad
    broad=$(sed -n "${broad_start},${ctx_end}p" "$file" 2>/dev/null)
    if echo "$broad" | grep -qE 'SI_ARCHITECTURE_32|SI_ARCHITECTURE_64' 2>/dev/null; then
        echo -e "  ${CYN}[SAFE]${NC} ${file#$USR_SRC/}:$lineno (SI_ARCHITECTURE_32/64 — unchanged)"
        echo "SAFE" >> "$results"
        return
    fi

    # Safe: isainfo / isa_list context
    if echo "$broad" | grep -qE 'isainfo|isa_list|isalist' 2>/dev/null; then
        echo -e "  ${CYN}[SAFE]${NC} ${file#$USR_SRC/}:$lineno (ISA list enumeration)"
        echo "SAFE" >> "$results"
        return
    fi

    # Safe: MACH normalized at top of file (amd64 remapped to i386)
    local file_head
    file_head=$(sed -n '1,80p' "$file" 2>/dev/null)
    if echo "$file_head" | grep -qE 'amd64.*&&.*MACH=.*i386|MACH=.*i386.*amd64' 2>/dev/null; then
        echo -e "  ${CYN}[SAFE]${NC} ${file#$USR_SRC/}:$lineno (MACH normalized at top of file)"
        echo "SAFE" >> "$results"
        return
    fi

    echo -e "  ${RED}[$category]${NC} ${file#$USR_SRC/}:$lineno"
    echo "         $content"
    echo "$category" >> "$results"
}

# ---------------------------------------------------------------
# 1. Shell scripts: uname -p/-i/-m comparisons
# ---------------------------------------------------------------
echo "=== SHELL SCRIPTS ==="
echo ""

for pattern in \
    'uname -p.*i386' \
    'uname -i.*i86pc' \
    'uname -m.*i86pc' \
    ; do
    echo "--- Pattern: $pattern ---"
    grep -rn --include='*.sh' --include='*.ksh' --include='*.csh' --include='*.bash' \
        "$pattern" "$USR_SRC/cmd" "$USR_SRC/lib" 2>/dev/null | \
        grep -v '^\s*#' | \
        while IFS=: read -r file lineno content rest; do
            classify "$file" "$lineno" "$content" "SHELL"
        done
    echo ""
done

# Also catch indirect patterns: variable set from uname then compared
echo "--- Pattern: MACH/arch variable compared to i386 ---"
grep -rn --include='*.sh' --include='*.ksh' \
    -E '"\$MACH"|"\$arch"|"\$isa"' "$USR_SRC/cmd" "$USR_SRC/lib" 2>/dev/null | \
    grep -E '= *"?i386"?' | \
    grep -v '^\s*#' | \
    while IFS=: read -r file lineno content rest; do
        classify "$file" "$lineno" "$content" "SHELL"
    done
echo ""

echo "--- Pattern: MACH/arch variable compared to i86pc ---"
grep -rn --include='*.sh' --include='*.ksh' \
    -E '"\$MACH"|"\$arch"|"\$isa"|"\$mach"' "$USR_SRC/cmd" "$USR_SRC/lib" 2>/dev/null | \
    grep -E '= *"?i86pc"?' | \
    grep -v '^\s*#' | \
    while IFS=: read -r file lineno content rest; do
        classify "$file" "$lineno" "$content" "SHELL"
    done
echo ""

# ---------------------------------------------------------------
# 2. C code: strcmp/strncmp against "i386" or "i86pc"
# ---------------------------------------------------------------
echo "=== C CODE ==="
echo ""

echo "--- strcmp/strncmp against 'i386' ---"
grep -rn --include='*.c' \
    -E 'str[n]?cmp\(.*"i386"' "$USR_SRC/cmd" "$USR_SRC/lib" 2>/dev/null | \
    grep -v '^\s*//' | grep -v '^\s*\*' | \
    while IFS=: read -r file lineno content rest; do
        classify "$file" "$lineno" "$content" "RUNTIME"
    done
echo ""

echo "--- strcmp/strncmp against 'i86pc' ---"
grep -rn --include='*.c' \
    -E 'str[n]?cmp\(.*"i86pc"' "$USR_SRC/cmd" "$USR_SRC/lib" 2>/dev/null | \
    grep -v '^\s*//' | grep -v '^\s*\*' | \
    while IFS=: read -r file lineno content rest; do
        classify "$file" "$lineno" "$content" "RUNTIME"
    done
echo ""

echo "--- be_is_isa(\"i386\") calls ---"
grep -rn --include='*.c' \
    'be_is_isa.*"i386"' "$USR_SRC" 2>/dev/null | \
    while IFS=: read -r file lineno content rest; do
        echo -e "  ${GRN}[FIXED]${NC} ${file#$USR_SRC/}:$lineno (be_is_isa remaps i386->amd64)"
        echo "FIXED" >> "$results"
    done
echo ""

# ---------------------------------------------------------------
# 3. Kernel: any remaining i386/i86pc in runtime context
# ---------------------------------------------------------------
echo "=== KERNEL (uts/) ==="
echo ""

echo "--- strcmp/strncmp against 'i386' in uts/ ---"
grep -rn --include='*.c' \
    -E 'str[n]?cmp\(.*"i386"' "$USR_SRC/uts" 2>/dev/null | \
    grep -v '^\s*//' | grep -v '^\s*\*' | \
    while IFS=: read -r file lineno content rest; do
        classify "$file" "$lineno" "$content" "RUNTIME"
    done
echo ""

echo "--- strcmp/strncmp against 'i86pc' in uts/ ---"
grep -rn --include='*.c' \
    -E 'str[n]?cmp\(.*"i86pc"' "$USR_SRC/uts" 2>/dev/null | \
    grep -v '^\s*//' | grep -v '^\s*\*' | \
    while IFS=: read -r file lineno content rest; do
        classify "$file" "$lineno" "$content" "RUNTIME"
    done
echo ""

# ---------------------------------------------------------------
# 4. Python/Perl scripts
# ---------------------------------------------------------------
echo "=== SCRIPTS (Python/Perl) ==="
echo ""

echo "--- Python/Perl with i386/i86pc comparisons ---"
grep -rn --include='*.py' --include='*.pl' \
    -E '"i386"|"i86pc"' "$USR_SRC/cmd" "$USR_SRC/lib" "$USR_SRC/tools" 2>/dev/null | \
    grep -vE '^\s*#|path|/platform/' | \
    while IFS=: read -r file lineno content rest; do
        classify "$file" "$lineno" "$content" "SCRIPT"
    done
echo ""

# ---------------------------------------------------------------
# Summary
# ---------------------------------------------------------------
echo "================================================================"
echo "SUMMARY"
echo "================================================================"

runtime_hits=$(grep -c '^RUNTIME$' "$results" 2>/dev/null || true)
shell_hits=$(grep -c '^SHELL$' "$results" 2>/dev/null || true)
script_hits=$(grep -c '^SCRIPT$' "$results" 2>/dev/null || true)
safe_count=$(grep -c '^SAFE$' "$results" 2>/dev/null || true)
fixed_count=$(grep -c '^FIXED$' "$results" 2>/dev/null || true)

runtime_hits=${runtime_hits:-0}
shell_hits=${shell_hits:-0}
script_hits=${script_hits:-0}
safe_count=${safe_count:-0}
fixed_count=${fixed_count:-0}

total_issues=$((runtime_hits + shell_hits + script_hits))

echo ""
echo -e "  ${RED}Runtime C issues:  $runtime_hits${NC}"
echo -e "  ${RED}Shell issues:      $shell_hits${NC}"
echo -e "  ${RED}Script issues:     $script_hits${NC}"
echo -e "  ${CYN}Safe (no action):  $safe_count${NC}"
echo -e "  ${GRN}Already fixed:     $fixed_count${NC}"
echo ""

if [ "$total_issues" -eq 0 ]; then
    echo -e "  ${GRN}ALL CLEAR — no remaining runtime breakages found.${NC}"
else
    echo -e "  ${RED}$total_issues issue(s) need attention.${NC}"
fi
echo ""
exit $total_issues
