From f7c67ee5dd07897cefb2884ad95899def23172f1 Mon Sep 17 00:00:00 2001 From: Jan De Landtsheer Date: Wed, 3 Sep 2025 17:06:57 +0200 Subject: [PATCH] Fix module dependency resolution issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix dependency resolution to use built modules from /lib/modules/6.12.44-Zero-OS instead of fresh container - Fix stage1/stage2 configuration mismatch (only using stage1 modules as intended) - Fix firmware parsing to ignore comments in modules.conf - Fix variable binding issues for incremental builds (FULL_KERNEL_VERSION, KERNEL_OUTPUT) - Module resolution now properly expands 31 → 48 modules with dependencies - Firmware requirements reduced from 157 bogus → 3 correct packages - All 48/48 resolved modules validated as available .ko files --- config/modules.conf | 10 +- scripts/build.sh | 210 ++++++++++++++++++++++--------- scripts/lib/initramfs.sh | 263 +++++++++++++++++++++++++++++++-------- 3 files changed, 368 insertions(+), 115 deletions(-) diff --git a/config/modules.conf b/config/modules.conf index 0b93c29..72bb359 100644 --- a/config/modules.conf +++ b/config/modules.conf @@ -2,12 +2,14 @@ # Format: STAGE:MODULE_NAME:FIRMWARE_PACKAGE (optional) # Focus on most common NIC modules to ensure networking works on most hardware -# Stage 1: ALL networking and essential boot modules -# All NICs must be loaded BEFORE network can come up +# Stage 1: Core subsystems + networking and essential boot modules +# All core subsystems and NICs must be loaded BEFORE network can come up +stage1:virtio:none # Core virtio subsystem (REQUIRED) +stage1:virtio_ring:none # Virtio ring buffer (REQUIRED) +stage1:virtio_pci:none # Virtio PCI bus stage1:virtio_net:none # Virtio network (VMs, cloud) stage1:virtio_scsi:none # Virtio SCSI (VMs, cloud) stage1:virtio_blk:none # Virtio block (VMs, cloud) -stage1:virtio_pci:none # Virtio PCI bus stage1:e1000:linux-firmware-intel # Intel E1000 (very common) stage1:e1000e:linux-firmware-intel # Intel E1000E (very common) stage1:r8169:linux-firmware-realtek # Realtek (most common desktop/server) @@ -25,9 +27,11 @@ stage1:atl1:none # Atheros L1 stage1:atl1e:none # Atheros L1E stage1:atl1c:none # Atheros L1C stage1:alx:none # Atheros Alx +stage1:libata:none # Core ATA subsystem (REQUIRED) stage1:scsi_mod:none # SCSI subsystem stage1:sd_mod:none # SCSI disk support stage1:ahci:none # SATA AHCI +stage1:nvme_core:none # Core NVMe subsystem (REQUIRED) stage1:nvme:none # NVMe storage stage1:tun:none # TUN/TAP for networking stage1:overlay:none # OverlayFS for containers diff --git a/scripts/build.sh b/scripts/build.sh index aca3ea6..2e64134 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -9,6 +9,7 @@ PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" # Source all libraries source "${SCRIPT_DIR}/lib/common.sh" +source "${SCRIPT_DIR}/lib/stages.sh" source "${SCRIPT_DIR}/lib/docker.sh" source "${SCRIPT_DIR}/lib/alpine.sh" source "${SCRIPT_DIR}/lib/components.sh" @@ -47,7 +48,7 @@ KEEP_ARTIFACTS="${KEEP_ARTIFACTS:-false}" # Display usage information function show_usage() { cat << EOF -Zero OS Alpine Initramfs Builder +Zero OS Alpine Initramfs Builder (Incremental) Usage: $0 [OPTIONS] @@ -55,20 +56,31 @@ Options: --clean Clean build (remove all artifacts first) --skip-tests Skip boot tests --keep-artifacts Keep build artifacts after completion + --force-rebuild Force rebuild all stages (ignore completion markers) + --rebuild-from=STAGE Force rebuild from specific stage onward + --show-stages Show stage completion status --help Show this help message Environment Variables: ALPINE_VERSION Alpine Linux version (default: 3.22) - KERNEL_VERSION Linux kernel version (default: 6.8.8) + KERNEL_VERSION Linux kernel version (default: 6.12.44) RUST_TARGET Rust compilation target (default: x86_64-unknown-linux-musl) OPTIMIZATION_LEVEL Optimization level: max|size|speed (default: max) DEBUG Enable debug output (default: 0) + FORCE_REBUILD Force rebuild all stages (default: false) Examples: - $0 # Basic build - $0 --clean # Clean build - $0 --container # Force container build - DEBUG=1 $0 # Build with debug output + $0 # Incremental build (skip completed stages) + $0 --clean # Clean build (remove artifacts + stage markers) + $0 --force-rebuild # Force rebuild all stages + $0 --rebuild-from=zinit_setup # Rebuild from zinit setup onward + $0 --show-stages # Show which stages are completed + DEBUG=1 $0 # Build with debug output + +Development Workflow: + ./scripts/dev-container.sh start # Start persistent container + ./scripts/dev-container.sh shell # Enter container for debugging + DEBUG=1 ./scripts/build.sh # Run incremental build inside container EOF } @@ -88,6 +100,22 @@ function parse_arguments() { KEEP_ARTIFACTS="true" shift ;; + --force-rebuild) + export FORCE_REBUILD="true" + shift + ;; + --rebuild-from=*) + export REBUILD_FROM_STAGE="${1#*=}" + export FORCE_REBUILD="true" + shift + ;; + --show-stages) + # Initialize stage tracking and show status + source "${SCRIPT_DIR}/lib/stages.sh" + stages_init + stages_status + exit 0 + ;; --help|-h) show_usage exit 0 @@ -174,82 +202,140 @@ function verify_configuration_files() { log_info "All configuration files verified" } -# Main build process +# Incremental build process with stage tracking function main_build_process() { - section_header "Starting Zero OS Alpine Initramfs Build" + section_header "Starting Zero OS Alpine Initramfs Build (Incremental)" local start_time=$(date +%s) - # Phase 1: Extract Alpine miniroot - alpine_extract_miniroot "$INSTALL_DIR" "$ALPINE_VERSION" + # Initialize stage tracking + stages_init - # Phase 2: Configure Alpine system - alpine_configure_repos "$INSTALL_DIR" "$ALPINE_VERSION" - alpine_configure_system "$INSTALL_DIR" + # Define stage wrapper functions + function stage_alpine_extract() { + alpine_extract_miniroot "$INSTALL_DIR" "$ALPINE_VERSION" + } - # Phase 3: Install Alpine packages (NO OpenRC) - alpine_install_packages "$INSTALL_DIR" "$PACKAGES_LIST" + function stage_alpine_configure() { + alpine_configure_repos "$INSTALL_DIR" "$ALPINE_VERSION" + alpine_configure_system "$INSTALL_DIR" + } - # Phase 3.5: Install firmware packages for hardware support - alpine_install_firmware "$INSTALL_DIR" "$FIRMWARE_CONF" + function stage_alpine_packages() { + alpine_install_packages "$INSTALL_DIR" "$PACKAGES_LIST" + } - # Phase 4: Build and install ThreeFold components - components_parse_sources_conf "$SOURCES_CONF" "$COMPONENTS_DIR" "$INSTALL_DIR" + function stage_alpine_firmware() { + alpine_install_firmware "$INSTALL_DIR" "$FIRMWARE_CONF" + } - # Phase 5: Verify component installation - components_verify_installation + function stage_components_build() { + components_parse_sources_conf "$SOURCES_CONF" "$COMPONENTS_DIR" "$INSTALL_DIR" + } - # Phase 6: Create placeholder initramfs for kernel build (chicken-egg problem) - local initramfs_archive="${DIST_DIR}/initramfs.cpio.xz" - safe_mkdir "$DIST_DIR" - log_info "Creating placeholder initramfs for initial kernel build" - safe_execute touch "$initramfs_archive" + function stage_components_verify() { + components_verify_installation + } - # Phase 7: Prepare kernel source and build modules (with placeholder initramfs) - log_info "Downloading and configuring kernel source for module build" - kernel_download_source "$KERNEL_DIR" "$KERNEL_VERSION" - kernel_apply_config "$KERNEL_DIR" "$initramfs_archive" "$KERNEL_CONFIG" + function stage_kernel_modules() { + # Create placeholder for kernel build + local initramfs_archive="${DIST_DIR}/initramfs.cpio.xz" + safe_mkdir "$DIST_DIR" + safe_execute touch "$initramfs_archive" + + # Download and build kernel modules + kernel_download_source "$KERNEL_DIR" "$KERNEL_VERSION" + kernel_apply_config "$KERNEL_DIR" "$initramfs_archive" "$KERNEL_CONFIG" + kernel_build_modules "$KERNEL_DIR" "$INSTALL_DIR" "$KERNEL_VERSION" + + # Set full kernel version for later stages + FULL_KERNEL_VERSION=$(kernel_get_full_version "$KERNEL_VERSION" "$KERNEL_CONFIG") + export FULL_KERNEL_VERSION + log_info "Full kernel version: ${FULL_KERNEL_VERSION}" + } - log_info "Building kernel modules for initramfs inclusion" - kernel_build_modules "$KERNEL_DIR" "$INSTALL_DIR" "$KERNEL_VERSION" + function stage_zinit_setup() { + initramfs_setup_zinit "$INSTALL_DIR" "$ZINIT_CONFIG_DIR" + } - # Phase 8: Setup zinit as init system - initramfs_setup_zinit "$INSTALL_DIR" "$ZINIT_CONFIG_DIR" + function stage_init_script() { + initramfs_install_init_script "$INSTALL_DIR" "${CONFIG_DIR}/init" + } - # Phase 9: Install critical /init script for initramfs boot - initramfs_install_init_script "$INSTALL_DIR" "${CONFIG_DIR}/init" + function stage_modules_setup() { + # Calculate full kernel version (needed for incremental builds when kernel_modules stage is skipped) + local full_kernel_version=$(kernel_get_full_version "$KERNEL_VERSION" "$KERNEL_CONFIG") + export FULL_KERNEL_VERSION="$full_kernel_version" + log_info "Using full kernel version: ${full_kernel_version}" + + initramfs_setup_modules "$INSTALL_DIR" "$MODULES_CONF" "$full_kernel_version" + } - # Phase 10: Setup 2-stage module loading - initramfs_setup_modules "$INSTALL_DIR" "$MODULES_CONF" "$KERNEL_VERSION" + function stage_modules_copy() { + # Ensure FULL_KERNEL_VERSION is set (for incremental builds) + if [[ -z "${FULL_KERNEL_VERSION:-}" ]]; then + FULL_KERNEL_VERSION=$(kernel_get_full_version "$KERNEL_VERSION" "$KERNEL_CONFIG") + export FULL_KERNEL_VERSION + fi + + log_info "About to copy modules - FULL_KERNEL_VERSION: ${FULL_KERNEL_VERSION}" + log_info "CONTAINER_MODULES_PATH: ${CONTAINER_MODULES_PATH:-not-set}" + initramfs_copy_resolved_modules "$INSTALL_DIR" "$FULL_KERNEL_VERSION" + } - # Phase 11: Aggressive cleanup for size optimization - alpine_aggressive_cleanup "$INSTALL_DIR" + function stage_cleanup() { + alpine_aggressive_cleanup "$INSTALL_DIR" + } - # Phase 12: Strip and UPX all binaries (temporarily skipped to reach kernel phase) - log_info "Skipping strip/UPX optimization to proceed to kernel compilation" - # initramfs_strip_and_upx "$INSTALL_DIR" + function stage_validation() { + initramfs_validate "$INSTALL_DIR" + } - # Phase 13: Validate initramfs - initramfs_validate "$INSTALL_DIR" + function stage_initramfs_create() { + local initramfs_archive="${DIST_DIR}/initramfs.cpio.xz" + initramfs_create_cpio "$INSTALL_DIR" "$initramfs_archive" + export INITRAMFS_ARCHIVE="$initramfs_archive" + } - # Phase 14: Create real initramfs archive (now with modules) - log_info "Creating real initramfs archive with all components and modules" - initramfs_create_cpio "$INSTALL_DIR" "$initramfs_archive" + function stage_initramfs_test() { + initramfs_test_archive "$INITRAMFS_ARCHIVE" + } - # Phase 15: Test archive integrity - initramfs_test_archive "$initramfs_archive" + function stage_kernel_build() { + local kernel_output="${DIST_DIR}/vmlinuz.efi" + kernel_build_with_initramfs "$KERNEL_CONFIG" "$INITRAMFS_ARCHIVE" "$kernel_output" + export KERNEL_OUTPUT="$kernel_output" + } - # Phase 16: Second kernel build with real embedded initramfs - local kernel_output="${DIST_DIR}/vmlinuz.efi" - log_info "Final kernel build: embedding complete initramfs" - kernel_build_with_initramfs "$KERNEL_CONFIG" "$initramfs_archive" "$kernel_output" + function stage_boot_tests() { + if [[ "$SKIP_TESTS" != "true" ]]; then + # Ensure KERNEL_OUTPUT is set (for incremental builds) + if [[ -z "${KERNEL_OUTPUT:-}" ]]; then + KERNEL_OUTPUT="${DIST_DIR}/vmlinuz.efi" + export KERNEL_OUTPUT + fi + testing_run_all "$KERNEL_OUTPUT" + fi + } - # Phase 17: Run boot tests (unless skipped) - if [[ "$SKIP_TESTS" != "true" ]]; then - testing_run_all "$kernel_output" - else - log_info "Skipping boot tests as requested" - fi + # Run all stages with incremental tracking + stage_run "alpine_extract" stage_alpine_extract + stage_run "alpine_configure" stage_alpine_configure + stage_run "alpine_packages" stage_alpine_packages + stage_run "alpine_firmware" stage_alpine_firmware + stage_run "components_build" stage_components_build + stage_run "components_verify" stage_components_verify + stage_run "kernel_modules" stage_kernel_modules + stage_run "zinit_setup" stage_zinit_setup + stage_run "init_script" stage_init_script + stage_run "modules_setup" stage_modules_setup + stage_run "modules_copy" stage_modules_copy + stage_run "cleanup" stage_cleanup + stage_run "validation" stage_validation + stage_run "initramfs_create" stage_initramfs_create + stage_run "initramfs_test" stage_initramfs_test + stage_run "kernel_build" stage_kernel_build + stage_run "boot_tests" stage_boot_tests # Calculate build time local end_time=$(date +%s) @@ -260,8 +346,8 @@ function main_build_process() { section_header "Build Complete" log_info "Build time: ${build_minutes}m ${build_seconds}s" log_info "Output files:" - log_info " Kernel: ${kernel_output} ($(get_file_size "$kernel_output"))" - log_info " Initramfs: ${initramfs_archive} ($(get_file_size "$initramfs_archive"))" + log_info " Kernel: ${KERNEL_OUTPUT} ($(get_file_size "$KERNEL_OUTPUT"))" + log_info " Initramfs: ${INITRAMFS_ARCHIVE} ($(get_file_size "$INITRAMFS_ARCHIVE"))" } # Cleanup build artifacts diff --git a/scripts/lib/initramfs.sh b/scripts/lib/initramfs.sh index 632c65e..8b5e0a9 100644 --- a/scripts/lib/initramfs.sh +++ b/scripts/lib/initramfs.sh @@ -118,9 +118,11 @@ function initramfs_setup_modules() { local stage1_modules=() local stage1_firmware=() - while IFS=: read -r stage module firmware; do + while IFS=: read -r stage module firmware_line; do if [[ "$stage" == "stage1" && -n "$module" ]]; then stage1_modules+=("$module") + # Extract firmware package name (before any comment) + local firmware=$(echo "$firmware_line" | sed 's/[[:space:]]*#.*//' | tr -d ' ') if [[ -n "$firmware" && "$firmware" != "none" ]]; then stage1_firmware+=("$firmware") required_firmware+=("$firmware") @@ -131,44 +133,25 @@ function initramfs_setup_modules() { local stage1_with_deps=() if [[ ${#stage1_modules[@]} -gt 0 ]]; then + log_info "Resolving dependencies for ${#stage1_modules[@]} stage1 modules: ${stage1_modules[*]}" stage1_with_deps=($(initramfs_resolve_module_dependencies "${stage1_modules[@]}")) + log_info "Stage1 expanded to ${#stage1_with_deps[@]} modules (including dependencies)" fi # Write stage1 list with dependencies printf '%s\n' "${stage1_with_deps[@]}" > "${modules_dir}/stage1.list" - # Create stage2 module list with dependencies and firmware - log_info "Resolving stage2 module dependencies (extended hardware)" - local stage2_modules=() - local stage2_firmware=() - - while IFS=: read -r stage module firmware; do - if [[ "$stage" == "stage2" && -n "$module" ]]; then - stage2_modules+=("$module") - if [[ -n "$firmware" && "$firmware" != "none" ]]; then - stage2_firmware+=("$firmware") - required_firmware+=("$firmware") - log_debug "Module $module requires firmware: $firmware" - fi - fi - done < <(grep "^stage2:" "$modules_conf") - - local stage2_with_deps=() - if [[ ${#stage2_modules[@]} -gt 0 ]]; then - stage2_with_deps=($(initramfs_resolve_module_dependencies "${stage2_modules[@]}")) - - # Remove stage1 modules from stage2 to avoid duplicates - local stage2_unique=() - for mod in "${stage2_with_deps[@]}"; do - if ! printf '%s\n' "${stage1_with_deps[@]}" | grep -q "^${mod}$"; then - stage2_unique+=("$mod") - fi - done - stage2_with_deps=("${stage2_unique[@]}") + # Debug: show what's in stage1 list + if [[ ${#stage1_with_deps[@]} -gt 50 ]]; then + log_warn "Stage1 module list unexpectedly large: ${#stage1_with_deps[@]} modules" + log_warn "This may indicate excessive dependency resolution" + log_debug "First 10 stage1 modules: ${stage1_with_deps[@]:0:10}" fi - # Write stage2 list with unique dependencies - printf '%s\n' "${stage2_with_deps[@]}" > "${modules_dir}/stage2.list" + # Create empty stage2 list (stage2 not used, only stage1) + log_info "Creating empty stage2 list (only using stage1 modules)" + echo > "${modules_dir}/stage2.list" + local stage2_with_deps=() # Create firmware requirements list (remove duplicates) local unique_firmware=($(printf '%s\n' "${required_firmware[@]}" | sort -u)) @@ -191,58 +174,119 @@ function initramfs_setup_modules() { # Report final counts local stage1_count=${#stage1_with_deps[@]} - local stage2_count=${#stage2_with_deps[@]} local firmware_count=${#unique_firmware[@]} log_info "Module configuration complete:" log_info " Stage1 (critical + deps): ${stage1_count} modules" - log_info " Stage2 (extended + deps): ${stage2_count} modules" + log_info " Stage2: disabled (only using stage1)" log_info " Required firmware packages: ${firmware_count}" - log_info " Total unique modules: $((stage1_count + stage2_count))" + log_info " Total modules: ${stage1_count}" } -# Resolve module dependencies recursively using modinfo +# Resolve module dependencies using built modules from initramfs function initramfs_resolve_module_dependencies() { local modules=("$@") local resolved_modules=() local processed_modules=() - log_debug "Resolving dependencies for modules: ${modules[*]}" + log_debug "Resolving dependencies for modules using built modules: ${modules[*]}" - # Function to recursively resolve a single module's dependencies + # Use full kernel version from build process, not host kernel (uname -r) + local kernel_version="${KERNEL_FULL_VERSION:-${FULL_KERNEL_VERSION:-}}" + if [[ -z "$kernel_version" ]]; then + # Fallback: calculate from KERNEL_VERSION + LOCALVERSION + source "${LIB_SCRIPT_DIR}/kernel.sh" + kernel_version=$(kernel_get_full_version "${KERNEL_VERSION:-6.12.44}" "${PROJECT_ROOT}/config/kernel.config") + fi + + # Use the built modules from initramfs directory (host path) + local modules_path="${PROJECT_ROOT}/initramfs/lib/modules/${kernel_version}" + + log_debug "Using target kernel version: ${kernel_version}" + log_debug "Looking for built modules at: ${modules_path}" + + if [[ ! -d "$modules_path" ]]; then + log_warn "Built modules not found at: $modules_path" + log_warn "Falling back to simple module list without dependencies" + printf '%s\n' "${modules[@]}" + return 0 + fi + + # Ensure depmod has been run on the built modules + if [[ ! -f "${modules_path}/modules.dep" ]]; then + log_info "Running depmod on built modules" + depmod -a -b "${PROJECT_ROOT}/initramfs" "$kernel_version" 2>/dev/null || { + log_warn "depmod failed, using simple module list" + printf '%s\n' "${modules[@]}" + return 0 + } + fi + + log_debug "Using built modules from: $modules_path" + + # Function to recursively resolve a single module's dependencies (with depth limit) function resolve_single_module() { local module="$1" + local depth="${2:-0}" + local max_depth=3 # Limit dependency depth to prevent explosion # Skip if already processed if printf '%s\n' "${processed_modules[@]}" | grep -q "^${module}$"; then return 0 fi + # Skip if we've gone too deep + if [[ $depth -gt $max_depth ]]; then + log_debug "Skipping $module - dependency depth limit ($max_depth) reached" + return 0 + fi + processed_modules+=("$module") - # Get module dependencies using modinfo + # Get module dependencies using modinfo from built modules local deps=() if command_exists "modinfo"; then - # Try to get dependencies - modinfo may fail for built-in modules local modinfo_output - if modinfo_output=$(modinfo "$module" 2>/dev/null); then - # Extract depends line and parse comma-separated dependencies - local depends_line=$(echo "$modinfo_output" | grep '^depends:' | head -1 | cut -d: -f2- | tr -d ' ') - if [[ -n "$depends_line" && "$depends_line" != "-" ]]; then - IFS=',' read -ra deps <<< "$depends_line" + local module_found=false + + # Find the actual module file + local module_file=$(find "$modules_path" -name "${module}.ko*" -type f | head -1) + + if [[ -n "$module_file" && -f "$module_file" ]]; then + # Use direct file path for modinfo + if modinfo_output=$(modinfo "$module_file" 2>/dev/null); then + module_found=true + + # Extract depends line and parse comma-separated dependencies + local depends_line=$(echo "$modinfo_output" | grep '^depends:' | head -1 | cut -d: -f2- | tr -d ' ') + if [[ -n "$depends_line" && "$depends_line" != "-" ]]; then + IFS=',' read -ra deps <<< "$depends_line" + if [[ ${#deps[@]} -gt 0 ]]; then + log_debug "Module $module (depth $depth) depends on: ${deps[*]}" + fi + fi fi else - log_debug "modinfo failed for module: $module (may be built-in)" + # Check if module might be built-in + if grep -q "^$module\$" "${modules_path}/modules.builtin" 2>/dev/null; then + log_debug "Module $module is built-in (no .ko file needed)" + module_found=true + elif [[ "$module" == "virtio" || "$module" == "virtio_ring" ]]; then + # Special case: virtio core components may be integrated into virtio_pci in newer kernels + log_debug "Module $module is likely integrated into virtio subsystem (skipping dependency)" + module_found=true + else + log_debug "Module $module not found - may be built-in or integrated" + fi fi else log_warn "modinfo not available, skipping dependency resolution" fi - # Recursively resolve dependencies first + # Recursively resolve dependencies first (with incremented depth) for dep in "${deps[@]}"; do if [[ -n "$dep" ]]; then - log_debug "Module $module depends on: $dep" - resolve_single_module "$dep" + resolve_single_module "$dep" $((depth + 1)) fi done @@ -266,7 +310,7 @@ function initramfs_resolve_module_dependencies() { fi done - log_debug "Resolved ${#unique_modules[@]} unique modules with dependencies" + log_debug "Resolved ${#unique_modules[@]} unique modules with dependencies from container" printf '%s\n' "${unique_modules[@]}" } @@ -622,7 +666,126 @@ function initramfs_test_archive() { log_info "Archive integrity test passed" } +# Copy resolved modules from container to initramfs +function initramfs_copy_resolved_modules() { + local initramfs_dir="$1" + local kernel_version="${2:-$(uname -r)}" + + log_info "ENTRY: initramfs_copy_resolved_modules called with:" + log_info " initramfs_dir: ${initramfs_dir}" + log_info " kernel_version: ${kernel_version}" + log_info " CONTAINER_MODULES_PATH: ${CONTAINER_MODULES_PATH:-not-set}" + + section_header "Copying Resolved Modules to Initramfs" + + local container_modules_path="${CONTAINER_MODULES_PATH:-/lib/modules/${kernel_version}}" + local initramfs_modules_dir="${initramfs_dir}/lib/modules/${kernel_version}" + + log_info "Container modules path: ${container_modules_path}" + log_info "Initramfs modules dir: ${initramfs_modules_dir}" + + if [[ ! -d "$container_modules_path" ]]; then + log_error "Container modules not found: $container_modules_path" + log_info "Available module directories:" + ls -la /lib/modules/ 2>/dev/null || log_error "No /lib/modules directory" + return 1 + fi + + log_info "Container modules directory exists, proceeding..." + + # Create initramfs modules directory + safe_mkdir "$initramfs_modules_dir" + + # Read the stage1 module list (only using stage1, no stage2) + local stage1_modules=() + + if [[ -f "${initramfs_modules_dir}/stage1.list" ]]; then + while IFS= read -r module; do + [[ -n "$module" ]] && stage1_modules+=("$module") + done < "${initramfs_modules_dir}/stage1.list" + fi + + local all_modules=("${stage1_modules[@]}") + + if [[ ${#all_modules[@]} -eq 0 ]]; then + log_warn "No modules to copy (empty stage1 module list)" + return 0 + fi + + log_info "Copying ${#all_modules[@]} stage1 modules to initramfs" + log_info "Stage1 modules: ${#stage1_modules[@]} (stage2 disabled)" + + # Debug: show what we're copying if the list is reasonable + if [[ ${#all_modules[@]} -lt 200 ]]; then + log_debug "Modules to copy: ${all_modules[*]}" + else + log_warn "Module list is very large (${#all_modules[@]}), showing sample:" + log_debug "First 10: ${all_modules[@]:0:10}" + log_debug "Last 10: ${all_modules[@]:-10}" + fi + + # Copy essential module metadata first + local essential_files=( + "modules.order" + "modules.builtin" + "modules.builtin.modinfo" + "modules.dep" + "modules.dep.bin" + "modules.symbols" + "modules.symbols.bin" + "modules.alias" + "modules.alias.bin" + "modules.devname" + ) + + for file in "${essential_files[@]}"; do + if [[ -f "${container_modules_path}/${file}" ]]; then + safe_execute cp "${container_modules_path}/${file}" "${initramfs_modules_dir}/" + log_debug "Copied module metadata: $file" + fi + done + + # Copy actual module files + local copied_count=0 + local failed_count=0 + + for module in "${all_modules[@]}"; do + local module_found=false + + # Try to find module file + local module_file=$(find "$container_modules_path" -name "${module}.ko*" -type f | head -1) + + if [[ -n "$module_file" && -f "$module_file" ]]; then + # Preserve directory structure + local rel_path="${module_file#${container_modules_path}/}" + local target_dir="${initramfs_modules_dir}/$(dirname "$rel_path")" + + safe_mkdir "$target_dir" + safe_execute cp "$module_file" "${initramfs_modules_dir}/${rel_path}" + + log_debug "Copied module: $module from $rel_path" + ((copied_count++)) + module_found=true + fi + + if [[ "$module_found" == "false" ]]; then + log_warn "Module not found in container: $module" + ((failed_count++)) + fi + done + + log_info "Module copy complete: ${copied_count} copied, ${failed_count} failed" + + # Run depmod in initramfs context if we have the tools + if command_exists "depmod" && [[ $copied_count -gt 0 ]]; then + log_info "Running depmod for initramfs modules" + safe_execute depmod -a -b "$initramfs_dir" "$kernel_version" + fi + + return 0 +} + # Export all functions at the end after they're all defined export -f initramfs_setup_zinit initramfs_setup_modules initramfs_resolve_module_dependencies export -f initramfs_install_init_script initramfs_create_module_scripts initramfs_strip_and_upx -export -f initramfs_create_cpio initramfs_validate initramfs_test_archive \ No newline at end of file +export -f initramfs_create_cpio initramfs_validate initramfs_test_archive initramfs_copy_resolved_modules \ No newline at end of file