#!/bin/bash # Alpine miniroot and package operations # Source common functions LIB_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "${LIB_SCRIPT_DIR}/common.sh" # Alpine configuration ALPINE_VERSION="${ALPINE_VERSION:-3.22}" ALPINE_ARCH="${ALPINE_ARCH:-x86_64}" ALPINE_MIRROR="${ALPINE_MIRROR:-https://dl-cdn.alpinelinux.org/alpine}" # Extract Alpine miniroot to target directory function alpine_extract_miniroot() { local target_dir="$1" local version="${2:-$ALPINE_VERSION}" local arch="${3:-$ALPINE_ARCH}" section_header "Extracting Alpine Miniroot" local url="${ALPINE_MIRROR}/v${version}/releases/${arch}/alpine-minirootfs-${version}.0-${arch}.tar.gz" local temp_file="/tmp/alpine-miniroot-${version}-${arch}.tar.gz" log_info "Alpine version: ${version}" log_info "Architecture: ${arch}" log_info "Target directory: ${target_dir}" # Clean target directory if [[ -d "$target_dir" ]]; then log_info "Cleaning existing target directory" safe_rmdir "$target_dir" fi safe_mkdir "$target_dir" # Download miniroot log_info "Downloading Alpine miniroot from: ${url}" safe_execute wget --progress=dot:giga -O "$temp_file" "$url" # Verify download if [[ ! -f "$temp_file" ]]; then log_error "Failed to download Alpine miniroot" return 1 fi local file_size=$(get_file_size "$temp_file") log_info "Downloaded miniroot size: ${file_size}" # Extract miniroot log_info "Extracting miniroot to: ${target_dir}" safe_execute tar -xzf "$temp_file" -C "$target_dir" # Cleanup download safe_execute rm "$temp_file" # Verify extraction if [[ ! -f "${target_dir}/etc/alpine-release" ]]; then log_error "Alpine miniroot extraction failed - missing alpine-release" return 1 fi local alpine_release=$(cat "${target_dir}/etc/alpine-release") log_info "Extracted Alpine release: ${alpine_release}" log_info "Alpine miniroot extraction complete" } # Setup chroot environment for package operations function alpine_setup_chroot() { local initramfs_dir="$1" section_header "Setting Up Alpine Chroot Environment" # Create essential directories safe_mkdir "${initramfs_dir}/proc" safe_mkdir "${initramfs_dir}/sys" safe_mkdir "${initramfs_dir}/dev" safe_mkdir "${initramfs_dir}/dev/pts" safe_mkdir "${initramfs_dir}/tmp" safe_mkdir "${initramfs_dir}/run" # Mount essential filesystems log_info "Mounting essential filesystems in chroot" if ! mountpoint -q "${initramfs_dir}/proc" 2>/dev/null; then safe_execute mount --bind /proc "${initramfs_dir}/proc" export CLEANUP_MOUNTS="${CLEANUP_MOUNTS:-} ${initramfs_dir}/proc" fi if ! mountpoint -q "${initramfs_dir}/sys" 2>/dev/null; then safe_execute mount --bind /sys "${initramfs_dir}/sys" export CLEANUP_MOUNTS="${CLEANUP_MOUNTS:-} ${initramfs_dir}/sys" fi if ! mountpoint -q "${initramfs_dir}/dev" 2>/dev/null; then safe_execute mount --bind /dev "${initramfs_dir}/dev" export CLEANUP_MOUNTS="${CLEANUP_MOUNTS:-} ${initramfs_dir}/dev" fi if ! mountpoint -q "${initramfs_dir}/dev/pts" 2>/dev/null; then safe_execute mount --bind /dev/pts "${initramfs_dir}/dev/pts" export CLEANUP_MOUNTS="${CLEANUP_MOUNTS:-} ${initramfs_dir}/dev/pts" fi # Setup resolv.conf for package downloads if [[ -f /etc/resolv.conf ]]; then safe_copy /etc/resolv.conf "${initramfs_dir}/etc/resolv.conf" fi log_info "Chroot environment setup complete" } # Cleanup chroot environment function alpine_cleanup_chroot() { local initramfs_dir="$1" section_header "Cleaning Up Alpine Chroot Environment" # Unmount filesystems in reverse order local mounts=( "${initramfs_dir}/dev/pts" "${initramfs_dir}/dev" "${initramfs_dir}/sys" "${initramfs_dir}/proc" ) for mount in "${mounts[@]}"; do if mountpoint -q "$mount" 2>/dev/null; then log_info "Unmounting: $mount" safe_execute umount "$mount" || log_warn "Failed to unmount $mount" fi done # Clear cleanup list export CLEANUP_MOUNTS="" log_info "Chroot cleanup complete" } # Install packages from packages.list (NO OpenRC) function alpine_install_packages() { local initramfs_dir="$1" local packages_file="$2" section_header "Installing Alpine Packages" if [[ ! -f "$packages_file" ]]; then log_error "Packages file not found: ${packages_file}" return 1 fi # Setup chroot environment alpine_setup_chroot "$initramfs_dir" # Update package repositories log_info "Updating package repositories" safe_execute chroot "$initramfs_dir" apk update # Read packages from file (excluding comments and empty lines) local packages=() while IFS= read -r line; do # Skip comments and empty lines if [[ "$line" =~ ^[[:space:]]*# ]] || [[ -z "${line// }" ]]; then continue fi packages+=("$line") done < "$packages_file" if [[ ${#packages[@]} -eq 0 ]]; then log_warn "No packages found in ${packages_file}" alpine_cleanup_chroot "$initramfs_dir" return 0 fi log_info "Installing ${#packages[@]} packages:" for pkg in "${packages[@]}"; do log_info " - $pkg" done # Install packages (NO OpenRC - explicitly exclude) log_info "Installing packages with apk" safe_execute chroot "$initramfs_dir" apk add --no-cache \ --no-scripts \ --clean-protected \ "${packages[@]}" # Verify critical packages are installed local critical_packages=("busybox" "musl" "alpine-baselayout") for pkg in "${critical_packages[@]}"; do if ! chroot "$initramfs_dir" apk info | grep -q "^${pkg}"; then log_error "Critical package missing: ${pkg}" alpine_cleanup_chroot "$initramfs_dir" return 1 fi done # Ensure no OpenRC packages were installed local openrc_packages=$(chroot "$initramfs_dir" apk info | grep -E "(openrc|sysvinit|systemd)" || true) if [[ -n "$openrc_packages" ]]; then log_warn "OpenRC-related packages detected:" echo "$openrc_packages" log_warn "These should be removed for zinit-only operation" fi alpine_cleanup_chroot "$initramfs_dir" log_info "Package installation complete" } # Aggressive cleanup to minimize size function alpine_aggressive_cleanup() { local initramfs_dir="$1" section_header "Aggressive Alpine Cleanup" log_info "Starting cleanup in: ${initramfs_dir}" # Remove documentation and man pages log_info "Removing documentation and man pages" safe_rmdir "${initramfs_dir}/usr/share/doc" safe_rmdir "${initramfs_dir}/usr/share/man" safe_rmdir "${initramfs_dir}/usr/share/info" safe_rmdir "${initramfs_dir}/usr/share/gtk-doc" # Remove locales except C/POSIX log_info "Removing locales (keeping C/POSIX only)" if [[ -d "${initramfs_dir}/usr/share/locale" ]]; then find "${initramfs_dir}/usr/share/locale" -mindepth 1 -maxdepth 1 -type d \ ! -name 'C' ! -name 'POSIX' -exec rm -rf {} + 2>/dev/null || true fi # Remove development headers and files log_info "Removing development files" safe_rmdir "${initramfs_dir}/usr/include" safe_rmdir "${initramfs_dir}/usr/lib/pkgconfig" safe_rmdir "${initramfs_dir}/usr/share/pkgconfig" safe_rmdir "${initramfs_dir}/lib/pkgconfig" # Remove static libraries log_info "Removing static libraries" find "${initramfs_dir}" -name "*.a" -type f -delete 2>/dev/null || true # Remove APK cache and database backup log_info "Removing APK cache and database backup" safe_rmdir "${initramfs_dir}/var/cache/apk" safe_rmdir "${initramfs_dir}/lib/apk/db" find "${initramfs_dir}/var/lib/apk" -name "*.old" -delete 2>/dev/null || true # Remove kernel source and headers if present log_info "Removing kernel development files" safe_rmdir "${initramfs_dir}/usr/src" safe_rmdir "${initramfs_dir}/lib/modules/*/build" safe_rmdir "${initramfs_dir}/lib/modules/*/source" # Remove Python bytecode and cache log_info "Removing Python cache files" find "${initramfs_dir}" -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null || true find "${initramfs_dir}" -name "*.pyc" -type f -delete 2>/dev/null || true find "${initramfs_dir}" -name "*.pyo" -type f -delete 2>/dev/null || true # Remove test files and examples log_info "Removing test files and examples" find "${initramfs_dir}" -path "*/test*" -type d -exec rm -rf {} + 2>/dev/null || true find "${initramfs_dir}" -path "*/example*" -type d -exec rm -rf {} + 2>/dev/null || true # Remove unnecessary files from usr/share log_info "Cleaning usr/share directory" local unwanted_share_dirs=( "applications" "icons" "pixmaps" "themes" "fonts" "sounds" "desktop-directories" "mime" "glib-2.0/schemas" ) for dir in "${unwanted_share_dirs[@]}"; do safe_rmdir "${initramfs_dir}/usr/share/${dir}" done # Remove large timezone data (keep only UTC) log_info "Trimming timezone data" if [[ -d "${initramfs_dir}/usr/share/zoneinfo" ]]; then find "${initramfs_dir}/usr/share/zoneinfo" -type f ! -name "UTC" ! -path "*/posix/*" -delete 2>/dev/null || true fi # Remove empty directories log_info "Removing empty directories" find "${initramfs_dir}" -type d -empty -delete 2>/dev/null || true # Calculate size after cleanup local total_size=$(du -sh "${initramfs_dir}" 2>/dev/null | cut -f1 || echo "unknown") log_info "Initramfs size after cleanup: ${total_size}" log_info "Aggressive cleanup complete" } # Configure Alpine repositories function alpine_configure_repos() { local initramfs_dir="$1" local version="${2:-$ALPINE_VERSION}" section_header "Configuring Alpine Repositories" local repos_file="${initramfs_dir}/etc/apk/repositories" # Create repositories file cat > "$repos_file" << EOF ${ALPINE_MIRROR}/v${version}/main ${ALPINE_MIRROR}/v${version}/community EOF log_info "Configured Alpine repositories for version ${version}" } # Set Alpine system settings function alpine_configure_system() { local initramfs_dir="$1" section_header "Configuring Alpine System Settings" # Set hostname echo "zero-os" > "${initramfs_dir}/etc/hostname" # Configure hosts file cat > "${initramfs_dir}/etc/hosts" << 'EOF' 127.0.0.1 localhost localhost.localdomain ::1 localhost localhost.localdomain EOF # Set timezone to UTC if [[ -f "${initramfs_dir}/usr/share/zoneinfo/UTC" ]]; then safe_execute ln -sf /usr/share/zoneinfo/UTC "${initramfs_dir}/etc/localtime" fi # Configure minimal profile cat > "${initramfs_dir}/etc/profile" << 'EOF' export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" export PS1='\h:\w\$ ' export HOME=/root export TERM=xterm umask 022 EOF # Set root shell safe_execute chroot "$initramfs_dir" chsh -s /bin/sh root log_info "Alpine system configuration complete" } # Install firmware packages for hardware support function alpine_install_firmware() { local initramfs_dir="$1" local firmware_conf="$2" section_header "Installing Alpine Firmware Packages" if [[ ! -f "$firmware_conf" ]]; then log_warn "Firmware configuration not found: ${firmware_conf}" log_info "Skipping firmware installation" return 0 fi # Setup chroot environment alpine_setup_chroot "$initramfs_dir" # Read firmware packages from config (excluding comments and empty lines) local firmware_packages=() while IFS=: read -r package description; do # Skip comments and empty lines if [[ "$package" =~ ^[[:space:]]*# ]] || [[ -z "${package// }" ]]; then continue fi # Trim whitespace package=$(echo "$package" | xargs) description=$(echo "$description" | xargs) if [[ -n "$package" ]]; then firmware_packages+=("$package") log_info " - ${package}: ${description}" fi done < "$firmware_conf" if [[ ${#firmware_packages[@]} -eq 0 ]]; then log_warn "No firmware packages found in ${firmware_conf}" alpine_cleanup_chroot "$initramfs_dir" return 0 fi log_info "Installing ${#firmware_packages[@]} firmware packages" # Install firmware packages safe_execute chroot "$initramfs_dir" apk add --no-cache "${firmware_packages[@]}" # List installed firmware files log_info "Checking installed firmware files:" local firmware_count=0 if [[ -d "${initramfs_dir}/lib/firmware" ]]; then firmware_count=$(find "${initramfs_dir}/lib/firmware" -type f | wc -l) local firmware_size=$(du -sh "${initramfs_dir}/lib/firmware" 2>/dev/null | cut -f1 || echo "0B") log_info " Firmware files: ${firmware_count} (${firmware_size})" # Log some example firmware files for verification log_debug "Sample firmware files:" find "${initramfs_dir}/lib/firmware" -type f | head -10 | while read -r fw; do log_debug " $(basename "$fw")" done else log_warn "No firmware directory found after installation" fi alpine_cleanup_chroot "$initramfs_dir" log_info "Firmware installation complete: ${firmware_count} files" } # Export functions export -f alpine_extract_miniroot alpine_setup_chroot alpine_cleanup_chroot export -f alpine_install_packages alpine_install_firmware alpine_aggressive_cleanup export -f alpine_configure_repos alpine_configure_system