#!/bin/bash # # ScoutFS kernel compatibility check # # Standalone script to verify whether scoutfs can build against a given # set of kernel headers. Used both locally and in CI matrix testing. # # Usage: check-kernel-compat.sh [KSRC_PATH] # Defaults to /lib/modules/$(uname -r)/build # # Exit 0 = compatible (build succeeded) # Exit 1 = incompatible (build failed or headers missing) # set -euo pipefail KSRC="${1:-/lib/modules/$(uname -r)/build}" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" REPO_ROOT="${SCRIPT_DIR}/.." # When used in the build repo, the scoutfs source is checked out # alongside. Allow override via SCOUTFS_SRC env var. SCOUTFS_SRC="${SCOUTFS_SRC:-${REPO_ROOT}/scoutfs}" echo "============================================" echo "ScoutFS Kernel Compatibility Check" echo "============================================" echo "Kernel headers: ${KSRC}" echo "ScoutFS source: ${SCOUTFS_SRC}" echo "" # --- Phase 1: Quick header checks --- echo "--- Phase 1: Header availability ---" if [ ! -d "$KSRC" ]; then echo "FAIL: Kernel headers directory not found: ${KSRC}" exit 1 fi if [ ! -f "$KSRC/Makefile" ]; then echo "FAIL: No Makefile in kernel build directory: ${KSRC}" exit 1 fi REQUIRED_HEADERS=( "include/linux/fs.h" "include/linux/blk_types.h" "include/linux/bio.h" "include/linux/net.h" "include/linux/shrinker.h" "include/linux/xattr.h" "include/linux/dcache.h" "include/linux/posix_acl.h" "include/linux/slab.h" "include/linux/rbtree.h" ) MISSING=0 for header in "${REQUIRED_HEADERS[@]}"; do if [ -f "${KSRC}/${header}" ]; then echo " OK: ${header}" else echo " MISSING: ${header}" MISSING=$((MISSING + 1)) fi done if [ "$MISSING" -gt 0 ]; then echo "" echo "FAIL: ${MISSING} required header(s) missing" exit 1 fi echo "" # --- Phase 2: Kernel version check --- echo "--- Phase 2: Kernel version ---" KMAJOR=$(grep '^VERSION' "$KSRC/Makefile" | head -1 | awk '{print $3}') KMINOR=$(grep '^PATCHLEVEL' "$KSRC/Makefile" | head -1 | awk '{print $3}') KSUB=$(grep '^SUBLEVEL' "$KSRC/Makefile" | head -1 | awk '{print $3}') echo " Detected: ${KMAJOR:-?}.${KMINOR:-?}.${KSUB:-?}" if [ -n "$KMAJOR" ] && [ -n "$KMINOR" ]; then KVER_NUM=$((KMAJOR * 100 + KMINOR)) if [ "$KVER_NUM" -lt 306 ]; then echo " FAIL: Kernel too old (minimum 3.6)" exit 1 fi echo " OK: Meets minimum version requirement (>= 3.6)" else echo " WARNING: Could not determine kernel version, proceeding anyway" fi echo "" # --- Phase 3: Compatibility feature detection --- echo "--- Phase 3: Compatibility feature detection ---" COMPAT_MAKEFILE="${SCOUTFS_SRC}/kmod/src/Makefile.kernelcompat" if [ -f "$COMPAT_MAKEFILE" ]; then TOTAL=0 DETECTED=0 # Parse the grep-based checks from Makefile.kernelcompat while IFS= read -r line; do if [[ "$line" =~ ifneq.*shell\ grep ]]; then TOTAL=$((TOTAL + 1)) # Extract the pattern and file from the grep command PATTERN=$(echo "$line" | sed -n "s/.*grep[[:space:]]*'\([^']*\)'.*/\1/p" | head -1) # Try with -s variant too if [ -z "$PATTERN" ]; then PATTERN=$(echo "$line" | sed -n "s/.*grep[[:space:]]*-s[[:space:]]*'\([^']*\)'.*/\1/p" | head -1) fi FILE=$(echo "$line" | sed -n 's/.*grep[^)]*[[:space:]]\([a-z].*\))/\1/p' | head -1) if [ -n "$PATTERN" ] && [ -n "$FILE" ] && [ -f "${KSRC}/${FILE}" ]; then if grep -q "$PATTERN" "${KSRC}/${FILE}" 2>/dev/null; then DETECTED=$((DETECTED + 1)) fi fi fi done < "$COMPAT_MAKEFILE" echo " Compat features detected: ${DETECTED}/${TOTAL}" echo " (This is informational — both old and new APIs are supported via shims)" else echo " WARNING: Makefile.kernelcompat not found at ${COMPAT_MAKEFILE}" echo " Skipping feature detection (set SCOUTFS_SRC to the scoutfs source directory)" fi echo "" # --- Phase 4: Actual build test --- echo "--- Phase 4: Build test ---" if [ ! -d "${SCOUTFS_SRC}/kmod" ]; then echo " SKIP: ScoutFS kmod source not found at ${SCOUTFS_SRC}/kmod" echo " (Header checks passed — build likely to succeed)" echo "" echo "RESULT: LIKELY COMPATIBLE (build test skipped)" exit 0 fi echo " Attempting module build..." BUILD_LOG=$(mktemp) if make -C "${SCOUTFS_SRC}/kmod" SK_KSRC="$KSRC" module > "$BUILD_LOG" 2>&1; then echo " BUILD: SUCCESS" make -C "${SCOUTFS_SRC}/kmod" SK_KSRC="$KSRC" clean > /dev/null 2>&1 || true rm -f "$BUILD_LOG" echo "" echo "============================================" echo "RESULT: COMPATIBLE" echo "============================================" exit 0 else echo " BUILD: FAILED" echo "" echo " Build log (last 30 lines):" tail -30 "$BUILD_LOG" | sed 's/^/ /' rm -f "$BUILD_LOG" echo "" echo "============================================" echo "RESULT: INCOMPATIBLE" echo "============================================" exit 1 fi