first commit

This commit is contained in:
robojerk 2025-08-21 07:31:52 -07:00
commit a61c0e9e0b
20 changed files with 2905 additions and 0 deletions

236
modules/bootloader.sh Normal file
View file

@ -0,0 +1,236 @@
#!/bin/bash
# Bootloader management module for bootc image creation
# This module handles GRUB installation and configuration
# Common functions are sourced by the main script
# Install GRUB bootloader
install_grub_bootloader() {
log_info "Installing bootloader..."
# Check if kernel exists
if [ -f "$WORK_DIR/mnt/boot/vmlinuz-6.12.41+deb13-amd64" ]; then
log_info "Kernel found in /boot location"
KERNEL_PATH="boot/vmlinuz-6.12.41+deb13-amd64"
INITRD_PATH="boot/initrd.img-6.12.41+deb13-amd64"
elif [ -f "$WORK_DIR/mnt/usr/lib/ostree-boot/vmlinuz-6.12.41+deb13-amd64" ]; then
log_info "Kernel found in OSTree location"
KERNEL_PATH="usr/lib/ostree-boot/vmlinuz-6.12.41+deb13-amd64"
INITRD_PATH="usr/lib/ostree-boot/initrd.img-6.12.41+deb13-amd64"
else
log_error "Kernel not found in expected locations"
log_info "Searching for kernel files..."
find "$WORK_DIR/mnt" -name "*vmlinuz*" -o -name "*kernel*" 2>/dev/null | head -10
exit 1
fi
# Install GRUB bootloader
log_info "Installing GRUB bootloader..."
# Create GRUB directory
sudo mkdir -p "$WORK_DIR/mnt/boot/grub"
# Temporarily unmount and remount for safer GRUB installation
log_info "Temporarily unmounting filesystem for GRUB installation..."
sudo umount "$WORK_DIR/mnt"
# Get the loop device from the disk module
if [ -z "$loop_dev" ]; then
log_error "Loop device not set. Cannot install bootloader."
return 1
fi
# Ensure the loop device path is correct
local device_path="${loop_dev}"
if [[ "$device_path" == /dev/* ]]; then
device_path="${device_path#/dev/}"
fi
log_info "Loop device: $loop_dev, device path: $device_path"
log_info "Mounting partition /dev/${device_path}p2"
sudo mount "/dev/${device_path}p2" "$WORK_DIR/mnt"
# Install GRUB to the disk
log_info "Installing GRUB to /dev/$device_path..."
if sudo grub-install --target=i386-pc --boot-directory="$WORK_DIR/mnt/boot" "/dev/$device_path"; then
log_info "GRUB installed successfully"
else
log_warn "GRUB installation failed, trying alternative method..."
# Try installing to the partition instead
if sudo grub-install --target=i386-pc --boot-directory="$WORK_DIR/mnt/boot" "/dev/${device_path}p2"; then
log_info "GRUB installed to partition successfully"
else
log_error "GRUB installation failed completely"
return 1
fi
fi
# Create GRUB configuration
log_info "Creating GRUB configuration..."
sudo tee "$WORK_DIR/mnt/boot/grub/grub.cfg" > /dev/null << EOF
set timeout=5
set default=0
menuentry "Debian Bootc" {
linux /$KERNEL_PATH root=/dev/sda2 rw console=tty0 console=ttyS0,115200n8
initrd /$INITRD_PATH
}
EOF
log_info "Bootloader installation completed"
}
# Install systemd-boot (for UEFI systems)
install_systemd_boot() {
log_info "Installing systemd-boot..."
# Create bootloader entries directory
sudo mkdir -p "$WORK_DIR/mnt/boot/loader/entries"
# Create bootloader entry
sudo tee "$WORK_DIR/mnt/boot/loader/entries/debian-bootc.conf" > /dev/null << EOF
title Debian Bootc
version 1
linux /ostree/debian-bootc/vmlinuz-6.12.41+deb13-amd64
initrd /ostree/debian-bootc/initramfs-6.12.41+deb13-amd64.img
options ostree=/ostree/boot.0/debian-bootc/0 rw console=tty0 console=ttyS0,115200n8
EOF
# Create loader configuration
sudo tee "$WORK_DIR/mnt/boot/loader/loader.conf" > /dev/null << EOF
default debian-bootc
timeout 5
editor no
EOF
log_info "systemd-boot installation completed"
}
# Verify bootloader installation
verify_bootloader() {
log_info "Verifying bootloader installation..."
# Check GRUB configuration
if [ -f "$WORK_DIR/mnt/boot/grub/grub.cfg" ]; then
log_info "GRUB configuration found"
else
log_error "GRUB configuration not found"
return 1
fi
# Check GRUB core image
if [ -f "$WORK_DIR/mnt/boot/grub/i386-pc/core.img" ]; then
log_info "GRUB core image found"
else
log_warn "GRUB core image not found - bootloader may not work"
fi
# Check kernel and initrd
if [ -f "$WORK_DIR/mnt/boot/vmlinuz-6.12.41+deb13-amd64" ]; then
log_info "Kernel found: vmlinuz-6.12.41+deb13-amd64"
else
log_error "Kernel not found"
return 1
fi
if [ -f "$WORK_DIR/mnt/boot/initrd.img-6.12.41+deb13-amd64" ]; then
log_info "Initrd found: initrd.img-6.12.41+deb13-amd64"
else
log_error "Initrd not found"
return 1
fi
log_info "Bootloader verification completed successfully"
return 0
}
# Show bootloader information
show_bootloader_info() {
log_info "Bootloader information:"
echo "GRUB configuration:"
if [ -f "$WORK_DIR/mnt/boot/grub/grub.cfg" ]; then
cat "$WORK_DIR/mnt/boot/grub/grub.cfg"
else
echo "GRUB configuration not found"
fi
echo ""
echo "Boot directory contents:"
ls -la "$WORK_DIR/mnt/boot/"
echo ""
echo "GRUB directory contents:"
if [ -d "$WORK_DIR/mnt/boot/grub" ]; then
ls -la "$WORK_DIR/mnt/boot/grub/"
else
echo "GRUB directory not found"
fi
}
# Customize GRUB configuration
customize_grub_config() {
local custom_config="$1"
if [ -n "$custom_config" ] && [ -f "$custom_config" ]; then
log_info "Applying custom GRUB configuration..."
sudo cp "$custom_config" "$WORK_DIR/mnt/boot/grub/grub.cfg"
log_info "Custom GRUB configuration applied"
else
log_warn "No custom GRUB configuration provided or file not found"
fi
}
# Set GRUB timeout
set_grub_timeout() {
local timeout="${1:-5}"
log_info "Setting GRUB timeout to ${timeout} seconds..."
# Update the existing grub.cfg with new timeout
sudo sed -i "s/set timeout=.*/set timeout=$timeout/" "$WORK_DIR/mnt/boot/grub/grub.cfg"
log_info "GRUB timeout set to ${timeout} seconds"
}
# Add custom GRUB menu entries
add_grub_menu_entry() {
local title="$1"
local kernel_path="$2"
local initrd_path="$3"
local root_device="${4:-/dev/sda2}"
local extra_params="${5:-}"
log_info "Adding GRUB menu entry: $title"
# Append to grub.cfg
sudo tee -a "$WORK_DIR/mnt/boot/grub/grub.cfg" > /dev/null << EOF
menuentry "$title" {
linux /$kernel_path root=$root_device rw console=tty0 console=ttyS0,115200n8 $extra_params
initrd /$initrd_path
}
EOF
log_info "GRUB menu entry added: $title"
}
# Print module usage
print_module_usage() {
echo "Usage: source modules/bootloader.sh"
echo "This module handles bootloader installation and configuration."
echo ""
echo "Available functions:"
echo " install_bootloader - Install GRUB bootloader"
echo " install_systemd_boot - Install systemd-boot (UEFI)"
echo " verify_bootloader - Verify bootloader installation"
echo " show_bootloader_info - Display bootloader information"
echo " customize_grub_config - Apply custom GRUB configuration"
echo " set_grub_timeout - Set GRUB timeout value"
echo " add_grub_menu_entry - Add custom GRUB menu entries"
echo ""
echo "Required variables:"
echo " WORK_DIR - Working directory for operations"
echo " loop_dev - Loop device for disk operations"
}

215
modules/chroot.sh Normal file
View file

@ -0,0 +1,215 @@
#!/bin/bash
# Chroot-based OSTree creation module for bootc image creation
# This module implements the debian-ostree-builder approach using chroot
# Common functions are sourced by the main script
# Create chroot environment
create_chroot_environment() {
log_info "Creating chroot environment..."
# Create chroot directory
local chroot_dir="$WORK_DIR/chroot"
mkdir -p "$chroot_dir"
# Install debootstrap if not available
if ! command -v debootstrap >/dev/null 2>&1; then
log_info "Installing debootstrap..."
sudo apt update
sudo apt install -y debootstrap
fi
# Create base Debian system
log_info "Creating base Debian system with debootstrap..."
sudo debootstrap --arch=amd64 --variant=minbase "$TARGET_DEBIAN_RELEASE" "$chroot_dir" http://deb.debian.org/debian/
# Mount necessary filesystems
log_info "Mounting necessary filesystems..."
sudo mount --bind /dev "$chroot_dir/dev"
sudo mount --bind /proc "$chroot_dir/proc"
sudo mount --bind /sys "$chroot_dir/sys"
sudo mount --bind /dev/pts "$chroot_dir/dev/pts"
log_info "Chroot environment created at: $chroot_dir"
}
# Install packages in chroot
install_chroot_packages() {
log_info "Installing packages in chroot..."
local chroot_dir="$WORK_DIR/chroot"
# Update package lists
sudo chroot "$chroot_dir" apt update
# Install essential packages
sudo chroot "$chroot_dir" apt install -y \
systemd \
systemd-sysv \
linux-image-amd64 \
linux-headers-amd64 \
grub-pc \
ostree \
ostree-boot \
network-manager \
openssh-server \
sudo \
curl \
wget \
vim \
less \
man-db
# Clean up package cache
sudo chroot "$chroot_dir" apt clean
log_info "Package installation completed"
}
# Initialize OSTree repository in chroot
init_ostree_repository() {
log_info "Initializing OSTree repository in chroot..."
local chroot_dir="$WORK_DIR/chroot"
# Initialize OSTree repository
sudo chroot "$chroot_dir" ostree init --repo=/ostree/repo --mode=bare-user
# Create stateroot for Debian
sudo chroot "$chroot_dir" ostree admin init-fs /
sudo chroot "$chroot_dir" ostree admin stateroot-init debian
log_info "OSTree repository initialized"
}
# Create OSTree commit from chroot
create_ostree_commit() {
log_info "Creating OSTree commit from chroot..."
local chroot_dir="$WORK_DIR/chroot"
# Commit the current system state
sudo chroot "$chroot_dir" ostree commit \
--repo=/ostree/repo \
--branch=debian/$TARGET_DEBIAN_RELEASE/x86_64 \
--subject="Debian $TARGET_DEBIAN_RELEASE system" \
--tree=dir=/
log_info "OSTree commit created"
}
# Deploy OSTree system
deploy_ostree_system() {
log_info "Deploying OSTree system..."
local chroot_dir="$WORK_DIR/chroot"
# Deploy the commit
sudo chroot "$chroot_dir" ostree admin deploy \
--os=debian \
--karg=console=tty0 \
--karg=console=ttyS0,115200n8 \
debian/$TARGET_DEBIAN_RELEASE/x86_64
log_info "OSTree system deployed"
}
# Configure bootloader in chroot
configure_chroot_bootloader() {
log_info "Configuring bootloader in chroot..."
local chroot_dir="$WORK_DIR/chroot"
# Install GRUB
sudo chroot "$chroot_dir" grub-install --target=i386-pc /dev/sda
# Generate GRUB configuration
sudo chroot "$chroot_dir" grub-mkconfig -o /boot/grub/grub.cfg
log_info "Bootloader configured"
}
# Copy chroot filesystem to mounted partition
copy_chroot_filesystem() {
log_info "Copying chroot filesystem to mounted partition..."
local chroot_dir="$WORK_DIR/chroot"
# Copy the entire chroot filesystem
sudo cp -r "$chroot_dir"/* "$WORK_DIR/mnt/"
# Create essential symlinks
sudo ln -sf usr/bin "$WORK_DIR/mnt/bin"
sudo ln -sf usr/lib "$WORK_DIR/mnt/lib"
sudo ln -sf usr/sbin "$WORK_DIR/mnt/sbin"
sudo ln -sf usr/lib64 "$WORK_DIR/mnt/lib64"
log_info "Chroot filesystem copied"
}
# Cleanup chroot environment
cleanup_chroot() {
log_info "Cleaning up chroot environment..."
local chroot_dir="$WORK_DIR/chroot"
# Unmount filesystems
sudo umount "$chroot_dir/dev/pts" 2>/dev/null || true
sudo umount "$chroot_dir/sys" 2>/dev/null || true
sudo umount "$chroot_dir/proc" 2>/dev/null || true
sudo umount "$chroot_dir/dev" 2>/dev/null || true
# Remove chroot directory
sudo rm -rf "$chroot_dir"
log_info "Chroot environment cleaned up"
}
# Show chroot information
show_chroot_info() {
log_info "Chroot information:"
local chroot_dir="$WORK_DIR/chroot"
if [ -d "$chroot_dir" ]; then
echo "Chroot directory: $chroot_dir"
echo "Chroot size: $(du -sh "$chroot_dir" 2>/dev/null || echo 'Unknown')"
if [ -d "$chroot_dir/ostree" ]; then
echo "OSTree repository: Found"
echo "OSTree size: $(du -sh "$chroot_dir/ostree" 2>/dev/null || echo 'Unknown')"
else
echo "OSTree repository: Not found"
fi
if [ -d "$chroot_dir/boot" ]; then
echo "Boot directory: Found"
echo "Kernel: $(ls "$chroot_dir/boot"/vmlinuz* 2>/dev/null || echo 'Not found')"
else
echo "Boot directory: Not found"
fi
else
echo "Chroot directory: Not found"
fi
}
# Print module usage
print_module_usage() {
echo "Usage: source modules/chroot.sh"
echo "This module implements chroot-based OSTree creation."
echo ""
echo "Available functions:"
echo " create_chroot_environment - Create chroot environment"
echo " install_chroot_packages - Install packages in chroot"
echo " init_ostree_repository - Initialize OSTree repository"
echo " create_ostree_commit - Create OSTree commit"
echo " deploy_ostree_system - Deploy OSTree system"
echo " configure_chroot_bootloader - Configure bootloader"
echo " copy_chroot_filesystem - Copy to mounted partition"
echo " cleanup_chroot - Cleanup chroot environment"
echo " show_chroot_info - Display chroot information"
echo ""
echo "Required variables:"
echo " WORK_DIR - Working directory for operations"
}

183
modules/common.sh Normal file
View file

@ -0,0 +1,183 @@
#!/bin/bash
# Common functions and utilities for bootc image creation modules
# This module provides shared functionality used across all other modules
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Logging functions
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_debug() {
echo -e "${BLUE}[DEBUG]${NC} $1"
}
# Global variables (will be set by calling script)
WORK_DIR=""
loop_dev=""
# Cleanup function
cleanup() {
if [ -n "$WORK_DIR" ] && [ -d "$WORK_DIR" ]; then
log_info "Cleaning up work directory..."
sudo umount "$WORK_DIR/mnt" 2>/dev/null || true
sudo losetup -d "$loop_dev" 2>/dev/null || true
sudo rm -rf "$WORK_DIR"
fi
}
# Set trap for cleanup
setup_cleanup() {
trap cleanup EXIT INT TERM
}
# Check prerequisites
check_prerequisites() {
log_info "Checking prerequisites..."
local required_commands=("podman" "qemu-img" "parted" "losetup" "mkfs.ext4" "grub-install" "grub-mkconfig")
for cmd in "${required_commands[@]}"; do
if ! command -v "$cmd" >/dev/null 2>&1; then
log_error "Required command '$cmd' not found"
exit 1
fi
done
# Check if container image exists
if ! podman image exists "$CONTAINER_IMAGE"; then
log_error "Container image '$CONTAINER_IMAGE' not found"
log_info "Please build the image first with: podman build -t $CONTAINER_IMAGE -f debian_bootc_dockerfile.txt ."
exit 1
fi
log_info "All prerequisites satisfied"
}
# Create output directory
create_output_dir() {
log_info "Creating output directory..."
mkdir -p "$OUTPUT_DIR"
}
# Create work directory
create_work_dir() {
WORK_DIR="./work-$$"
log_info "Creating work directory: $WORK_DIR"
mkdir -p "$WORK_DIR"
}
# Validate configuration
validate_config() {
if [ -z "$CONTAINER_IMAGE" ]; then
log_error "CONTAINER_IMAGE not set"
exit 1
fi
if [ -z "$OUTPUT_DIR" ]; then
log_error "OUTPUT_DIR not set"
exit 1
fi
if [ -z "$IMAGE_SIZE_GB" ]; then
log_error "IMAGE_SIZE_GB not set"
exit 1
fi
log_debug "Configuration validated successfully"
}
# Show progress
show_progress() {
local step="$1"
local total="$2"
local current="$3"
local percentage=$((current * 100 / total))
local bar_length=30
local filled=$((bar_length * current / total))
local empty=$((bar_length - filled))
printf "\r["
printf "%${filled}s" | tr ' ' '#'
printf "%${empty}s" | tr ' ' '-'
printf "] %d%% - %s" "$percentage" "$step"
if [ "$current" -eq "$total" ]; then
echo
fi
}
# Check disk space
check_disk_space() {
# Get the directory where the main script is located
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
local required_space=$((IMAGE_SIZE_GB * 1024 * 1024 * 1024)) # Convert GB to bytes
local available_space=$(df "$script_dir" | awk 'NR==2 {print $4}')
# Convert available space to GB for comparison
local available_gb=$((available_space / 1024 / 1024 / 1024))
log_debug "Disk space check: Required: ${IMAGE_SIZE_GB}GB, Available: ${available_gb}GB"
if [ "$available_gb" -lt "$IMAGE_SIZE_GB" ]; then
log_error "Insufficient disk space. Required: ${IMAGE_SIZE_GB}GB, Available: ${available_gb}GB"
exit 1
fi
log_debug "Disk space check passed"
}
# Wait for user confirmation
confirm_action() {
local message="$1"
local default="${2:-n}"
if [ "$default" = "y" ]; then
read -p "$message [Y/n]: " -r
if [[ $REPLY =~ ^[Nn]$ ]]; then
return 1
fi
else
read -p "$message [y/N]: " -r
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
return 1
fi
fi
return 0
}
# Print module usage
print_module_usage() {
local module_name="$1"
echo "Usage: source modules/$module_name.sh"
echo "This module provides common functionality for bootc image creation."
echo ""
echo "Available functions:"
echo " log_info, log_warn, log_error, log_debug - Logging functions"
echo " cleanup, setup_cleanup - Cleanup management"
echo " check_prerequisites - Validate system requirements"
echo " create_output_dir, create_work_dir - Directory management"
echo " validate_config - Configuration validation"
echo " show_progress - Progress display"
echo " check_disk_space - Disk space validation"
echo " confirm_action - User confirmation prompts"
}

136
modules/disk.sh Normal file
View file

@ -0,0 +1,136 @@
#!/bin/bash
# Disk management module for bootc image creation
# This module handles disk image creation, partitioning, and filesystem setup
# Common functions are sourced by the main script
# Create and partition disk image
create_disk_image_work() {
log_info "Creating disk image..."
# Check disk space first (temporarily disabled for debugging)
# check_disk_space
# Create raw image first to ensure proper sizing
log_info "Creating raw image with size: ${IMAGE_SIZE_GB}GB"
dd if=/dev/zero of="$OUTPUT_DIR/debian-bootc.raw" bs=1M count=$((IMAGE_SIZE_GB * 1024))
# Create loop device
loop_dev=$(sudo losetup --find --show "$OUTPUT_DIR/debian-bootc.raw")
log_info "Using loop device: $loop_dev"
# Export the loop device variable so other modules can use it
export loop_dev
# Partition the disk with proper GPT layout including BIOS Boot Partition
log_info "Partitioning disk..."
sudo parted "$loop_dev" mklabel gpt
# Create 1MB BIOS Boot Partition for GRUB
sudo parted "$loop_dev" mkpart primary 1MiB 2MiB
sudo parted "$loop_dev" set 1 bios_grub on
# Create main system partition
sudo parted "$loop_dev" mkpart primary ext4 2MiB 100%
sudo parted "$loop_dev" set 2 boot on
# Verify partitions were created correctly
log_info "Verifying partition layout..."
sudo parted "$loop_dev" print
# Create filesystem on the main partition (partition 2)
log_info "Creating filesystem..."
sudo mkfs.ext4 "${loop_dev}p2"
# Mount the main partition (partition 2)
log_info "Mounting partition..."
mkdir -p "$WORK_DIR/mnt"
sudo mount "${loop_dev}p2" "$WORK_DIR/mnt"
log_info "Device size: $(sudo blockdev --getsize64 $loop_dev) bytes"
}
# Create essential directories
create_essential_directories() {
log_info "Creating essential directories..."
# Create essential directories individually
sudo mkdir -p "$WORK_DIR/mnt/usr"
sudo mkdir -p "$WORK_DIR/mnt/etc"
sudo mkdir -p "$WORK_DIR/mnt/var"
sudo mkdir -p "$WORK_DIR/mnt/home"
sudo mkdir -p "$WORK_DIR/mnt/root"
sudo mkdir -p "$WORK_DIR/mnt/boot"
sudo mkdir -p "$WORK_DIR/mnt/proc"
sudo mkdir -p "$WORK_DIR/mnt/sys"
sudo mkdir -p "$WORK_DIR/mnt/dev"
sudo mkdir -p "$WORK_DIR/mnt/tmp"
sudo mkdir -p "$WORK_DIR/mnt/run"
sudo mkdir -p "$WORK_DIR/mnt/media"
sudo mkdir -p "$WORK_DIR/mnt/mnt"
log_info "Essential directories created"
}
# Unmount and cleanup disk
cleanup_disk() {
log_info "Cleaning up disk operations..."
if [ -n "$WORK_DIR" ] && [ -d "$WORK_DIR/mnt" ]; then
sudo umount "$WORK_DIR/mnt" 2>/dev/null || true
fi
if [ -n "$loop_dev" ]; then
sudo losetup -d "$loop_dev" 2>/dev/null || true
fi
}
# Get disk information
get_disk_info() {
if [ -n "$loop_dev" ]; then
log_info "Disk information:"
sudo parted "$loop_dev" print
echo ""
sudo fdisk -l "$loop_dev"
else
log_warn "No loop device available for disk info"
fi
}
# Verify disk integrity
verify_disk_integrity() {
log_info "Verifying disk integrity..."
if [ ! -f "$OUTPUT_DIR/debian-bootc.raw" ]; then
log_error "Raw disk image not found"
return 1
fi
local image_size=$(stat -c%s "$OUTPUT_DIR/debian-bootc.raw")
local expected_size=$((IMAGE_SIZE_GB * 1024 * 1024 * 1024))
if [ "$image_size" -ne "$expected_size" ]; then
log_error "Disk image size mismatch. Expected: $expected_size, Got: $image_size"
return 1
fi
log_info "Disk integrity verified successfully"
return 0
}
# Print module usage
print_module_usage() {
echo "Usage: source modules/disk.sh"
echo "This module handles disk image creation and management."
echo ""
echo "Available functions:"
echo " create_disk_image - Create and partition disk image"
echo " create_essential_directories - Create required directory structure"
echo " cleanup_disk - Unmount and cleanup disk operations"
echo " get_disk_info - Display disk partition information"
echo " verify_disk_integrity - Verify disk image integrity"
echo ""
echo "Required variables:"
echo " OUTPUT_DIR - Output directory for images"
echo " IMAGE_SIZE_GB - Image size in gigabytes"
echo " WORK_DIR - Working directory for operations"
}

188
modules/filesystem.sh Normal file
View file

@ -0,0 +1,188 @@
#!/bin/bash
# Filesystem management module for bootc image creation
# This module handles container filesystem extraction and setup
# Common functions are sourced by the main script
# Extract container filesystem
extract_container_filesystem() {
log_info "Extracting container filesystem..."
# Change ownership to allow container to write
log_info "Setting directory permissions..."
sudo chown -R 1000:1000 "$WORK_DIR/mnt"
# Extract container filesystem directly
log_info "Extracting container filesystem..."
podman run --rm -v "$WORK_DIR/mnt:/extract" "$CONTAINER_IMAGE" \
/bin/bash -c "
cd /extract
echo 'Starting filesystem extraction...'
# Copy the main system directories with verbose output
echo 'Copying /usr...'
cp -rv /usr . 2>&1 || echo 'Copy of /usr failed'
echo 'Copying /etc...'
cp -rv /etc . 2>&1 || echo 'Copy of /etc failed'
echo 'Copying /var...'
cp -rv /var . 2>&1 || echo 'Copy of /var failed'
echo 'Copying /home...'
cp -rv /home . 2>&1 || echo 'Copy of /home failed'
echo 'Copying /root...'
cp -rv /root . 2>&1 || echo 'Copy of /root failed'
echo 'Copying /boot...'
cp -rv /boot . 2>&1 || echo 'Copy of /boot failed'
# Create symlinks for traditional compatibility (usr-merge structure)
echo 'Creating symlinks for usr-merge compatibility...'
if [ -d usr/bin ]; then
ln -sf usr/bin bin
echo 'Created bin -> usr/bin symlink'
fi
if [ -d usr/lib ]; then
ln -sf usr/lib lib
echo 'Created lib -> usr/lib symlink'
fi
if [ -d usr/lib64 ]; then
ln -sf usr/lib64 lib64
echo 'Created lib64 -> usr/lib64 symlink'
fi
if [ -d usr/sbin ]; then
ln -sf usr/sbin sbin
echo 'Created sbin -> usr/sbin symlink'
fi
echo 'Filesystem extraction completed'
echo 'Final directory listing:'
ls -la
echo 'Checking usr directory:'
ls -la usr/
echo 'Checking if critical directories exist:'
[ -d usr/lib ] && echo 'usr/lib exists' || echo 'usr/lib MISSING'
[ -d usr/sbin ] && echo 'usr/sbin exists' || echo 'usr/sbin MISSING'
[ -d usr/bin ] && echo 'usr/bin exists' || echo 'usr/bin MISSING'
echo 'Checking boot directory:'
ls -la boot/
"
# Restore proper ownership for the final image
log_info "Restoring proper ownership..."
sudo chown -R root:root "$WORK_DIR/mnt"
log_info "Filesystem extraction completed"
}
# Fix file permissions
fix_file_permissions() {
log_info "Fixing critical file permissions..."
# Fix sudo permissions
sudo chmod 4755 "$WORK_DIR/mnt/usr/bin/sudo" # Set setuid bit for sudo
sudo chown root:root "$WORK_DIR/mnt/usr/bin/sudo" # Ensure sudo is owned by root
# Fix home directory permissions (use UID 1000 which is typically the first user)
sudo chown -R 1000:1000 "$WORK_DIR/mnt/home/debian"
sudo chmod 755 "$WORK_DIR/mnt/home/debian"
# Ensure critical system tools have proper permissions
sudo chmod 755 "$WORK_DIR/mnt/usr/bin/ip" 2>/dev/null || echo "ip command not found"
sudo chmod 755 "$WORK_DIR/mnt/usr/bin/ping" 2>/dev/null || echo "ping command not found"
sudo chmod 755 "$WORK_DIR/mnt/bin/shutdown" 2>/dev/null || echo "shutdown command not found"
sudo chmod 755 "$WORK_DIR/mnt/bin/halt" 2>/dev/null || echo "halt command not found"
sudo chmod 755 "$WORK_DIR/mnt/bin/poweroff" 2>/dev/null || echo "poweroff command not found"
# Set proper permissions for system directories
sudo chmod 1777 "$WORK_DIR/mnt/tmp"
sudo chmod 755 "$WORK_DIR/mnt/proc" "$WORK_DIR/mnt/sys" "$WORK_DIR/mnt/dev" \
"$WORK_DIR/mnt/run" "$WORK_DIR/mnt/media" "$WORK_DIR/mnt/mnt"
log_info "File permissions fixed"
}
# Verify filesystem integrity
verify_filesystem_integrity() {
log_info "Verifying filesystem integrity..."
local critical_dirs=("usr" "etc" "var" "boot" "home")
local missing_dirs=()
for dir in "${critical_dirs[@]}"; do
if [ ! -d "$WORK_DIR/mnt/$dir" ]; then
missing_dirs+=("$dir")
fi
done
if [ ${#missing_dirs[@]} -gt 0 ]; then
log_error "Missing critical directories: ${missing_dirs[*]}"
return 1
fi
# Check for critical symlinks
local critical_symlinks=("bin" "lib" "sbin")
local missing_symlinks=()
for symlink in "${critical_symlinks[@]}"; do
if [ ! -L "$WORK_DIR/mnt/$symlink" ]; then
missing_symlinks+=("$symlink")
fi
done
if [ ${#missing_symlinks[@]} -gt 0 ]; then
log_error "Missing critical symlinks: ${missing_symlinks[*]}"
return 1
fi
# Check for kernel and initrd
if [ ! -f "$WORK_DIR/mnt/boot/vmlinuz-6.12.41+deb13-amd64" ]; then
log_error "Kernel not found in expected location"
return 1
fi
if [ ! -f "$WORK_DIR/mnt/boot/initrd.img-6.12.41+deb13-amd64" ]; then
log_error "Initrd not found in expected location"
return 1
fi
log_info "Filesystem integrity verified successfully"
return 0
}
# Show filesystem statistics
show_filesystem_stats() {
log_info "Filesystem statistics:"
echo "Directory sizes:"
du -sh "$WORK_DIR/mnt"/* 2>/dev/null | sort -hr
echo ""
echo "File counts:"
find "$WORK_DIR/mnt" -type f | wc -l | xargs echo "Total files:"
find "$WORK_DIR/mnt" -type d | wc -l | xargs echo "Total directories:"
find "$WORK_DIR/mnt" -type l | wc -l | xargs echo "Total symlinks:"
echo ""
echo "Largest files:"
find "$WORK_DIR/mnt" -type f -exec ls -lh {} + 2>/dev/null | sort -k5 -hr | head -10
}
# Print module usage
print_module_usage() {
echo "Usage: source modules/filesystem.sh"
echo "This module handles filesystem extraction and management."
echo ""
echo "Available functions:"
echo " extract_container_filesystem - Extract container filesystem"
echo " fix_file_permissions - Fix critical file permissions"
echo " verify_filesystem_integrity - Verify filesystem integrity"
echo " show_filesystem_stats - Display filesystem statistics"
echo ""
echo "Required variables:"
echo " CONTAINER_IMAGE - Container image to extract from"
echo " WORK_DIR - Working directory for operations"
}

171
modules/formats.sh Normal file
View file

@ -0,0 +1,171 @@
#!/bin/bash
# Output format conversion module for bootc image creation
# This module handles conversion to different output formats (QCOW2, ISO, IMG)
# Common functions are sourced by the main script
# Convert to QCOW2
convert_to_qcow2() {
log_info "Converting to QCOW2..."
# Unmount before conversion
sudo umount "$WORK_DIR/mnt"
# Convert raw image to QCOW2
qemu-img convert -f raw -O qcow2 "$OUTPUT_DIR/debian-bootc.raw" "$OUTPUT_DIR/debian-bootc.qcow2"
# Keep the raw image for VM use
log_info "Raw image kept: $OUTPUT_DIR/debian-bootc.raw"
log_info "QCOW2 image created: $OUTPUT_DIR/debian-bootc-simple.qcow2"
# Show final image info
ls -lh "$OUTPUT_DIR/debian-bootc.qcow2"
}
# Convert to ISO
convert_to_iso() {
log_info "Converting to ISO..."
# Unmount before conversion
sudo umount "$WORK_DIR/mnt"
# Create temporary directory for ISO contents
local iso_temp="$WORK_DIR/iso-temp"
mkdir -p "$iso_temp"
# Copy filesystem to temporary directory
log_info "Preparing ISO contents..."
sudo cp -r "$WORK_DIR/mnt"/* "$iso_temp/"
# Create bootable ISO
log_info "Creating bootable ISO..."
genisoimage -o "$OUTPUT_DIR/debian-bootc.iso" \
-b isolinux/isolinux.bin \
-c isolinux/boot.cat \
-no-emul-boot \
-boot-load-size 4 \
-boot-info-table \
-r \
-J \
-v \
"$iso_temp"
# Cleanup temporary directory
sudo rm -rf "$iso_temp"
log_info "ISO image created: $OUTPUT_DIR/debian-bootc.iso"
ls -lh "$OUTPUT_DIR/debian-bootc.iso"
}
# Convert to IMG (raw format)
convert_to_img() {
log_info "Converting to IMG format..."
# Unmount before conversion
sudo umount "$WORK_DIR/mnt"
# Copy raw image to IMG
cp "$OUTPUT_DIR/debian-bootc.raw" "$OUTPUT_DIR/debian-bootc.img"
log_info "IMG image created: $OUTPUT_DIR/debian-bootc.img"
ls -lh "$OUTPUT_DIR/debian-bootc.img"
}
# Convert to VMDK (VMware format)
convert_to_vmdk() {
log_info "Converting to VMDK..."
# Unmount before conversion
sudo umount "$WORK_DIR/mnt"
# Convert raw image to VMDK
qemu-img convert -f raw -O vmdk "$OUTPUT_DIR/debian-bootc.raw" "$OUTPUT_DIR/debian-bootc.vmdk"
log_info "VMDK image created: $OUTPUT_DIR/debian-bootc.vmdk"
ls -lh "$OUTPUT_DIR/debian-bootc.vmdk"
}
# Convert to VDI (VirtualBox format)
convert_to_vdi() {
log_info "Converting to VDI..."
# Unmount before conversion
sudo umount "$WORK_DIR/mnt"
# Convert raw image to VDI
qemu-img convert -f raw -O vdi "$OUTPUT_DIR/debian-bootc.raw" "$OUTPUT_DIR/debian-bootc.vdi"
log_info "VDI image created: $OUTPUT_DIR/debian-bootc.vdi"
ls -lh "$OUTPUT_DIR/debian-bootc.vdi"
}
# Convert to multiple formats
convert_to_all_formats() {
log_info "Converting to all supported formats..."
# Unmount before conversion
sudo umount "$WORK_DIR/mnt"
# Convert to all formats
convert_to_qcow2
convert_to_iso
convert_to_img
convert_to_vmdk
convert_to_vdi
log_info "All format conversions completed!"
# Show all created images
echo ""
log_info "Created images:"
ls -lh "$OUTPUT_DIR"/debian-bootc.*
}
# Show format information
show_format_info() {
log_info "Format information:"
if [ -f "$OUTPUT_DIR/debian-bootc.raw" ]; then
echo "Raw image: $(ls -lh "$OUTPUT_DIR/debian-bootc.raw")"
fi
if [ -f "$OUTPUT_DIR/debian-bootc.qcow2" ]; then
echo "QCOW2 image: $(ls -lh "$OUTPUT_DIR/debian-bootc.qcow2")"
fi
if [ -f "$OUTPUT_DIR/debian-bootc.iso" ]; then
echo "ISO image: $(ls -lh "$OUTPUT_DIR/debian-bootc.iso")"
fi
if [ -f "$OUTPUT_DIR/debian-bootc.img" ]; then
echo "IMG image: $(ls -lh "$OUTPUT_DIR/debian-bootc.img")"
fi
if [ -f "$OUTPUT_DIR/debian-bootc.vmdk" ]; then
echo "VMDK image: $(ls -lh "$OUTPUT_DIR/debian-bootc.vmdk")"
fi
if [ -f "$OUTPUT_DIR/debian-bootc.vdi" ]; then
echo "VDI image: $(ls -lh "$OUTPUT_DIR/debian-bootc.vdi")"
fi
}
# Print module usage
print_module_usage() {
echo "Usage: source modules/formats.sh"
echo "This module handles output format conversion."
echo ""
echo "Available functions:"
echo " convert_to_qcow2 - Convert to QCOW2 format"
echo " convert_to_iso - Convert to ISO format"
echo " convert_to_img - Convert to IMG format"
echo " convert_to_vmdk - Convert to VMDK format"
echo " convert_to_vdi - Convert to VDI format"
echo " convert_to_all_formats - Convert to all formats"
echo " show_format_info - Display format information"
echo ""
echo "Required variables:"
echo " OUTPUT_DIR - Output directory for images"
echo " WORK_DIR - Working directory for operations"
}