aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-01-23 22:57:21 -0600
committerCraig Jennings <c@cjennings.net>2026-01-23 22:57:21 -0600
commite4ee55f9706d5567f45b6b4f6f007c09709fdfea (patch)
tree93b017f7d3b8c76c752e25b2e7c380019bc33355
parent4560cbdc55e6bd5abe643806e4115d67313db564 (diff)
downloadarchangel-e4ee55f9706d5567f45b6b4f6f007c09709fdfea.tar.gz
archangel-e4ee55f9706d5567f45b6b4f6f007c09709fdfea.zip
Phase 2.1: Implement btrfs support
- Create lib/btrfs.sh with full btrfs installation functions - Subvolume layout matching ZFS datasets (10 subvols) - Snapper configuration with timeline policy - GRUB + grub-btrfs for snapshot boot menu - Update disk.sh for filesystem-aware partition type - Update archangel with install_btrfs() path - Update build.sh to include lib/btrfs.sh - Update plan with Phase 2.7 (test) and 2.8 (LUKS)
-rwxr-xr-xbuild.sh3
-rwxr-xr-xcustom/archangel165
-rw-r--r--custom/lib/btrfs.sh423
-rw-r--r--custom/lib/disk.sh11
-rw-r--r--docs/PLAN-archangel-btrfs.org34
-rw-r--r--docs/session-context.org101
6 files changed, 656 insertions, 81 deletions
diff --git a/build.sh b/build.sh
index 8a1b74c..b3546bb 100755
--- a/build.sh
+++ b/build.sh
@@ -417,6 +417,9 @@ if grep -q "file_permissions=" "$PROFILE_DIR/profiledef.sh"; then
/)/ i\ ["/usr/local/bin/lib/zfs.sh"]="0:0:755"
}' "$PROFILE_DIR/profiledef.sh"
sed -i '/^file_permissions=(/,/)/ {
+ /)/ i\ ["/usr/local/bin/lib/btrfs.sh"]="0:0:755"
+ }' "$PROFILE_DIR/profiledef.sh"
+ sed -i '/^file_permissions=(/,/)/ {
/)/ i\ ["/etc/shadow"]="0:0:400"
}' "$PROFILE_DIR/profiledef.sh"
fi
diff --git a/custom/archangel b/custom/archangel
index f9bc637..c887a4d 100755
--- a/custom/archangel
+++ b/custom/archangel
@@ -29,6 +29,7 @@ source "$SCRIPT_DIR/lib/common.sh"
source "$SCRIPT_DIR/lib/config.sh"
source "$SCRIPT_DIR/lib/disk.sh"
source "$SCRIPT_DIR/lib/zfs.sh"
+source "$SCRIPT_DIR/lib/btrfs.sh"
#############################
# Configuration
@@ -80,7 +81,15 @@ echo ""
preflight_checks() {
require_root
- zfs_preflight
+}
+
+# Filesystem-specific preflight (called after filesystem is selected)
+filesystem_preflight() {
+ if [[ "$FILESYSTEM" == "zfs" ]]; then
+ zfs_preflight
+ elif [[ "$FILESYSTEM" == "btrfs" ]]; then
+ btrfs_preflight
+ fi
}
#############################
@@ -108,9 +117,9 @@ gather_input() {
fi
fi
- # Btrfs not yet implemented
- if [[ "$FILESYSTEM" == "btrfs" ]]; then
- error "Btrfs support not yet implemented. Use FILESYSTEM=zfs"
+ # Validate filesystem choice
+ if [[ "$FILESYSTEM" != "zfs" && "$FILESYSTEM" != "btrfs" ]]; then
+ error "Invalid FILESYSTEM: $FILESYSTEM (must be 'zfs' or 'btrfs')"
fi
# Determine RAID level if not specified
@@ -143,12 +152,6 @@ gather_input() {
echo ""
select_filesystem
-
- # Check for btrfs (not yet implemented)
- if [[ "$FILESYSTEM" == "btrfs" ]]; then
- error "Btrfs support not yet implemented. Please select ZFS."
- fi
-
get_hostname
get_timezone
get_locale
@@ -156,8 +159,17 @@ gather_input() {
get_disks
get_raid_level
get_wifi
- get_encryption_choice
- [[ "$NO_ENCRYPT" != "yes" ]] && get_zfs_passphrase
+
+ # Encryption handling (filesystem-specific)
+ if [[ "$FILESYSTEM" == "zfs" ]]; then
+ get_encryption_choice
+ [[ "$NO_ENCRYPT" != "yes" ]] && get_zfs_passphrase
+ elif [[ "$FILESYSTEM" == "btrfs" ]]; then
+ # Btrfs encryption (LUKS) not yet implemented - Phase 2.8
+ info "Note: Btrfs encryption (LUKS) will be available in a future update."
+ NO_ENCRYPT="yes"
+ fi
+
get_root_password
get_ssh_config
show_summary
@@ -882,6 +894,44 @@ EOF
info "Base system installed."
}
+install_base_btrfs() {
+ step "Installing Base System (Btrfs)"
+
+ info "Updating pacman keys..."
+ pacman-key --init
+ pacman-key --populate archlinux
+
+ info "Installing base packages (this takes a while)..."
+ yes "" | pacstrap -K /mnt \
+ base \
+ base-devel \
+ linux-lts \
+ linux-lts-headers \
+ linux-firmware \
+ btrfs-progs \
+ grub \
+ grub-btrfs \
+ efibootmgr \
+ snapper \
+ snap-pac \
+ networkmanager \
+ avahi \
+ nss-mdns \
+ openssh \
+ git \
+ vim \
+ sudo \
+ zsh \
+ nodejs \
+ npm \
+ ttf-dejavu \
+ fzf \
+ wget \
+ wireless-regdb
+
+ info "Base system installed."
+}
+
configure_system() {
step "Configuring System"
@@ -1392,6 +1442,37 @@ print_summary() {
echo ""
}
+print_btrfs_summary() {
+ echo ""
+ echo "╔═══════════════════════════════════════════════════════════════╗"
+ echo "║ Installation Complete! ║"
+ echo "╚═══════════════════════════════════════════════════════════════╝"
+ echo ""
+ echo "System Configuration:"
+ echo " Hostname: $HOSTNAME"
+ echo " Timezone: $TIMEZONE"
+ echo " Filesystem: Btrfs"
+ echo ""
+ echo "Btrfs Snapshot Features:"
+ echo " - Boot from any snapshot via GRUB menu"
+ echo " - Genesis snapshot: pristine post-install state"
+ echo " - Pre/post pacman snapshots via snap-pac"
+ echo " - Timeline snapshots: 6 hourly, 7 daily, 2 weekly, 1 monthly"
+ echo ""
+ echo "GRUB Boot Menu:"
+ echo " - Select 'Arch Linux snapshots' submenu to boot from snapshots"
+ echo " - Snapshots auto-added when created by snapper"
+ echo ""
+ echo "Useful Commands:"
+ echo " List snapshots: snapper -c root list"
+ echo " Manual snapshot: snapper -c root create -d 'description'"
+ echo " Rollback: snapper -c root rollback <number>"
+ echo " Compare: snapper -c root diff <num1>..<num2>"
+ echo ""
+ info "Installation log: $LOGFILE"
+ echo ""
+}
+
#############################
# Main
#############################
@@ -1401,14 +1482,27 @@ main() {
preflight_checks
check_config
gather_input
+ filesystem_preflight
# Unattended installation begins
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
- echo "Beginning unattended installation..."
+ echo "Beginning unattended installation ($FILESYSTEM)..."
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
+ if [[ "$FILESYSTEM" == "zfs" ]]; then
+ install_zfs
+ elif [[ "$FILESYSTEM" == "btrfs" ]]; then
+ install_btrfs
+ fi
+}
+
+#############################
+# ZFS Installation Path
+#############################
+
+install_zfs() {
partition_disks
create_zfs_pool
create_datasets
@@ -1429,6 +1523,51 @@ main() {
print_summary
}
+#############################
+# Btrfs Installation Path
+#############################
+
+install_btrfs() {
+ # Get partition references
+ local root_part=$(get_root_partition "${SELECTED_DISKS[0]}")
+ local efi_part=$(get_efi_partition "${SELECTED_DISKS[0]}")
+
+ # Partition and format
+ partition_disk "${SELECTED_DISKS[0]}"
+ format_efi "$efi_part"
+ create_btrfs_volume "$root_part"
+
+ # Create and mount subvolumes
+ create_btrfs_subvolumes "$root_part"
+ mount_btrfs_subvolumes "$root_part"
+
+ # Mount EFI
+ mkdir -p /mnt/efi
+ mount "$efi_part" /mnt/efi
+
+ # Install base system
+ install_base_btrfs
+
+ # Configure system
+ configure_system
+ configure_wifi
+ configure_ssh
+ generate_btrfs_fstab "$root_part" "$efi_part"
+ configure_btrfs_initramfs
+ configure_grub "$efi_part"
+ configure_snapper
+ configure_btrfs_services
+ configure_btrfs_pacman_hook
+ copy_archsetup
+
+ # Genesis snapshot
+ create_btrfs_genesis_snapshot
+
+ # Cleanup
+ btrfs_cleanup
+ print_btrfs_summary
+}
+
trap 'error "Installation interrupted!"' INT TERM
main "$@"
diff --git a/custom/lib/btrfs.sh b/custom/lib/btrfs.sh
new file mode 100644
index 0000000..c264fce
--- /dev/null
+++ b/custom/lib/btrfs.sh
@@ -0,0 +1,423 @@
+#!/usr/bin/env bash
+# btrfs.sh - Btrfs-specific functions for archangel installer
+# Source this file after common.sh, config.sh, disk.sh
+
+#############################
+# Btrfs Constants
+#############################
+
+# Mount options for btrfs subvolumes
+BTRFS_OPTS="noatime,compress=zstd,space_cache=v2,discard=async"
+
+# Subvolume layout (matches ZFS dataset structure)
+# Format: "name:mountpoint:extra_opts"
+BTRFS_SUBVOLS=(
+ "@:/::"
+ "@home:/home::"
+ "@snapshots:/.snapshots::"
+ "@var_log:/var/log::"
+ "@var_cache:/var/cache::"
+ "@tmp:/tmp::nosuid,nodev"
+ "@var_tmp:/var/tmp::nosuid,nodev"
+ "@media:/media::compress=no"
+ "@vms:/vms::nodatacow,compress=no"
+ "@var_lib_docker:/var/lib/docker::"
+)
+
+#############################
+# Btrfs Pre-flight
+#############################
+
+btrfs_preflight() {
+ step "Checking Btrfs Requirements"
+
+ # Check for btrfs-progs
+ if ! command_exists mkfs.btrfs; then
+ error "btrfs-progs not installed. Cannot create btrfs filesystem."
+ fi
+ info "btrfs-progs available."
+
+ # Check for required tools
+ require_command btrfs
+ require_command grub-install
+
+ info "Btrfs preflight checks passed."
+}
+
+#############################
+# Btrfs Volume Creation
+#############################
+
+create_btrfs_volume() {
+ local partition="$1"
+
+ step "Creating Btrfs Filesystem"
+
+ info "Formatting $partition as btrfs..."
+ mkfs.btrfs -f -L "archroot" "$partition" || error "Failed to create btrfs filesystem"
+
+ info "Btrfs filesystem created on $partition"
+}
+
+#############################
+# Subvolume Creation
+#############################
+
+create_btrfs_subvolumes() {
+ local partition="$1"
+
+ step "Creating Btrfs Subvolumes"
+
+ # Mount the raw btrfs volume temporarily
+ mount "$partition" /mnt || error "Failed to mount btrfs volume"
+
+ # Create each subvolume
+ for subvol_spec in "${BTRFS_SUBVOLS[@]}"; do
+ IFS=':' read -r name mountpoint extra <<< "$subvol_spec"
+ info "Creating subvolume: $name -> $mountpoint"
+ btrfs subvolume create "/mnt/$name" || error "Failed to create subvolume $name"
+ done
+
+ # Unmount raw volume
+ umount /mnt
+
+ info "Created ${#BTRFS_SUBVOLS[@]} subvolumes."
+}
+
+#############################
+# Btrfs Mount Functions
+#############################
+
+mount_btrfs_subvolumes() {
+ local partition="$1"
+
+ step "Mounting Btrfs Subvolumes"
+
+ # Mount root subvolume first
+ info "Mounting @ -> /mnt"
+ mount -o "subvol=@,$BTRFS_OPTS" "$partition" /mnt || error "Failed to mount root subvolume"
+
+ # Create mount points and mount remaining subvolumes
+ for subvol_spec in "${BTRFS_SUBVOLS[@]}"; do
+ IFS=':' read -r name mountpoint extra <<< "$subvol_spec"
+
+ # Skip root, already mounted
+ [[ "$name" == "@" ]] && continue
+
+ # Build mount options
+ local opts="subvol=$name,$BTRFS_OPTS"
+
+ # Apply extra options (override defaults where specified)
+ if [[ -n "$extra" ]]; then
+ # Handle compress=no by removing compress from opts and not adding it
+ if [[ "$extra" == *"compress=no"* ]]; then
+ opts=$(echo "$opts" | sed 's/,compress=zstd//')
+ fi
+ # Handle nodatacow
+ if [[ "$extra" == *"nodatacow"* ]]; then
+ opts="$opts,nodatacow"
+ opts=$(echo "$opts" | sed 's/,compress=zstd//')
+ fi
+ # Handle nosuid,nodev for tmp
+ if [[ "$extra" == *"nosuid"* ]]; then
+ opts="$opts,nosuid,nodev"
+ fi
+ fi
+
+ info "Mounting $name -> /mnt$mountpoint"
+ mkdir -p "/mnt$mountpoint"
+ mount -o "$opts" "$partition" "/mnt$mountpoint" || error "Failed to mount $name"
+ done
+
+ # Set permissions on tmp directories
+ chmod 1777 /mnt/tmp /mnt/var/tmp
+
+ info "All subvolumes mounted."
+}
+
+#############################
+# Fstab Generation
+#############################
+
+generate_btrfs_fstab() {
+ local partition="$1"
+ local efi_partition="$2"
+
+ step "Generating fstab"
+
+ local uuid
+ uuid=$(blkid -s UUID -o value "$partition")
+
+ # Start with header
+ cat > /mnt/etc/fstab << EOF
+# /etc/fstab - Btrfs subvolume mounts
+# IMPORTANT: Using subvol= NOT subvolid= for snapshot compatibility
+# Generated by archangel installer
+
+EOF
+
+ # Add each subvolume
+ for subvol_spec in "${BTRFS_SUBVOLS[@]}"; do
+ IFS=':' read -r name mountpoint extra <<< "$subvol_spec"
+
+ # Build mount options
+ local opts="subvol=$name,$BTRFS_OPTS"
+
+ # Apply extra options
+ if [[ -n "$extra" ]]; then
+ if [[ "$extra" == *"compress=no"* ]]; then
+ opts=$(echo "$opts" | sed 's/,compress=zstd//')
+ fi
+ if [[ "$extra" == *"nodatacow"* ]]; then
+ opts="$opts,nodatacow"
+ opts=$(echo "$opts" | sed 's/,compress=zstd//')
+ fi
+ if [[ "$extra" == *"nosuid"* ]]; then
+ opts="$opts,nosuid,nodev"
+ fi
+ fi
+
+ echo "UUID=$uuid $mountpoint btrfs $opts 0 0" >> /mnt/etc/fstab
+ done
+
+ # Add EFI partition
+ local efi_uuid
+ efi_uuid=$(blkid -s UUID -o value "$efi_partition")
+ echo "" >> /mnt/etc/fstab
+ echo "# EFI System Partition" >> /mnt/etc/fstab
+ echo "UUID=$efi_uuid /efi vfat defaults,noatime 0 2" >> /mnt/etc/fstab
+
+ info "fstab generated with ${#BTRFS_SUBVOLS[@]} btrfs mounts + EFI"
+}
+
+#############################
+# Snapper Configuration
+#############################
+
+configure_snapper() {
+ step "Configuring Snapper"
+
+ # Snapper config for root
+ # Note: snapper expects /.snapshots to exist and be a subvolume
+ info "Creating snapper config for root..."
+
+ arch-chroot /mnt snapper -c root create-config / || error "Failed to create snapper config"
+
+ # Snapper creates its own .snapshots subvolume, but we already have @snapshots
+ # Delete snapper's and use ours
+ arch-chroot /mnt btrfs subvolume delete /.snapshots 2>/dev/null || true
+ mkdir -p /mnt/.snapshots
+
+ # Set snapper timeline settings
+ # Keep: 6 hourly, 7 daily, 2 weekly, 1 monthly
+ info "Configuring snapshot retention policy..."
+ cat > /mnt/etc/snapper/configs/root << 'EOF'
+# Snapper config for root filesystem
+SUBVOLUME="/"
+FSTYPE="btrfs"
+QGROUP=""
+
+# Automatic timeline snapshots
+TIMELINE_CREATE="yes"
+TIMELINE_CLEANUP="yes"
+
+# Retention policy
+TIMELINE_MIN_AGE="1800"
+TIMELINE_LIMIT_HOURLY="6"
+TIMELINE_LIMIT_DAILY="7"
+TIMELINE_LIMIT_WEEKLY="2"
+TIMELINE_LIMIT_MONTHLY="1"
+TIMELINE_LIMIT_YEARLY="0"
+
+# Cleanup settings
+NUMBER_CLEANUP="yes"
+NUMBER_MIN_AGE="1800"
+NUMBER_LIMIT="50"
+NUMBER_LIMIT_IMPORTANT="10"
+
+# User access
+ALLOW_USERS=""
+ALLOW_GROUPS=""
+
+# Sync ACL
+SYNC_ACL="no"
+
+# Background comparison
+BACKGROUND_COMPARISON="yes"
+
+# Empty pre-post cleanup
+EMPTY_PRE_POST_CLEANUP="yes"
+EMPTY_PRE_POST_MIN_AGE="1800"
+EOF
+
+ # Enable snapper timers
+ arch-chroot /mnt systemctl enable snapper-timeline.timer
+ arch-chroot /mnt systemctl enable snapper-cleanup.timer
+
+ info "Snapper configured with timeline snapshots enabled."
+}
+
+#############################
+# GRUB Configuration
+#############################
+
+configure_grub() {
+ local efi_partition="$1"
+
+ step "Configuring GRUB Bootloader"
+
+ # Mount EFI partition
+ mkdir -p /mnt/efi
+ mount "$efi_partition" /mnt/efi
+
+ # Configure GRUB defaults
+ info "Setting GRUB configuration..."
+ cat > /mnt/etc/default/grub << 'EOF'
+# GRUB configuration for btrfs root with snapshots
+GRUB_DEFAULT=0
+GRUB_TIMEOUT=5
+GRUB_DISTRIBUTOR="Arch"
+GRUB_CMDLINE_LINUX_DEFAULT="loglevel=3 quiet"
+GRUB_CMDLINE_LINUX=""
+
+# Btrfs snapshot boot support
+GRUB_BTRFS_GRUB_DIRNAME="/efi/grub"
+
+# Disable os-prober (single-boot system)
+GRUB_DISABLE_OS_PROBER=true
+EOF
+
+ # Install GRUB to EFI
+ info "Installing GRUB to EFI partition..."
+ arch-chroot /mnt grub-install --target=x86_64-efi --efi-directory=/efi --bootloader-id=GRUB \
+ || error "GRUB installation failed"
+
+ # Generate GRUB config
+ info "Generating GRUB configuration..."
+ arch-chroot /mnt grub-mkconfig -o /boot/grub/grub.cfg \
+ || error "Failed to generate GRUB config"
+
+ # Enable grub-btrfsd for automatic snapshot menu updates
+ info "Enabling grub-btrfs daemon..."
+ arch-chroot /mnt systemctl enable grub-btrfsd
+
+ info "GRUB configured with btrfs snapshot support."
+}
+
+#############################
+# Pacman Snapshot Hook
+#############################
+
+configure_btrfs_pacman_hook() {
+ step "Configuring Pacman Snapshot Hook"
+
+ # snap-pac handles this automatically when installed
+ # Just verify it's set up
+ info "snap-pac will create pre/post snapshots for pacman transactions."
+ info "Snapshots visible in GRUB menu via grub-btrfs."
+}
+
+#############################
+# Genesis Snapshot
+#############################
+
+create_btrfs_genesis_snapshot() {
+ step "Creating Genesis Snapshot"
+
+ # Use snapper to create the genesis snapshot
+ arch-chroot /mnt snapper -c root create --description "genesis" \
+ || error "Failed to create genesis snapshot"
+
+ info "Genesis snapshot created."
+ info "Restore with: snapper -c root rollback <number>"
+
+ # Show the snapshot
+ arch-chroot /mnt snapper -c root list
+}
+
+#############################
+# Btrfs Services
+#############################
+
+configure_btrfs_services() {
+ step "Configuring System Services"
+
+ # Enable standard services
+ arch-chroot /mnt systemctl enable NetworkManager
+ arch-chroot /mnt systemctl enable avahi-daemon
+
+ # Snapper timers (already enabled in configure_snapper)
+
+ # grub-btrfsd (already enabled in configure_grub)
+
+ info "System services configured."
+}
+
+#############################
+# Btrfs Initramfs
+#############################
+
+configure_btrfs_initramfs() {
+ step "Configuring Initramfs for Btrfs"
+
+ # Backup original
+ cp /mnt/etc/mkinitcpio.conf /mnt/etc/mkinitcpio.conf.bak
+
+ # Remove archiso drop-in if present
+ if [[ -f /mnt/etc/mkinitcpio.conf.d/archiso.conf ]]; then
+ info "Removing archiso drop-in config..."
+ rm -f /mnt/etc/mkinitcpio.conf.d/archiso.conf
+ fi
+
+ # Create proper linux-lts preset
+ info "Creating linux-lts preset..."
+ cat > /mnt/etc/mkinitcpio.d/linux-lts.preset << 'EOF'
+# mkinitcpio preset file for linux-lts
+
+PRESETS=(default fallback)
+
+ALL_kver="/boot/vmlinuz-linux-lts"
+
+default_image="/boot/initramfs-linux-lts.img"
+
+fallback_image="/boot/initramfs-linux-lts-fallback.img"
+fallback_options="-S autodetect"
+EOF
+
+ # Configure hooks for btrfs
+ # btrfs module is built into kernel, but we need the btrfs hook for multi-device
+ sed -i 's/^HOOKS=.*/HOOKS=(base udev microcode modconf kms keyboard keymap consolefont block filesystems fsck)/' \
+ /mnt/etc/mkinitcpio.conf
+
+ # Regenerate initramfs
+ info "Regenerating initramfs..."
+ arch-chroot /mnt mkinitcpio -P
+
+ info "Initramfs configured for btrfs."
+}
+
+#############################
+# Btrfs Cleanup
+#############################
+
+btrfs_cleanup() {
+ step "Cleaning Up Btrfs"
+
+ # Unmount in reverse order
+ info "Unmounting subvolumes..."
+
+ # Unmount EFI first
+ umount /mnt/efi 2>/dev/null || true
+
+ # Unmount all btrfs subvolumes (reverse order)
+ for ((i=${#BTRFS_SUBVOLS[@]}-1; i>=0; i--)); do
+ IFS=':' read -r name mountpoint extra <<< "${BTRFS_SUBVOLS[$i]}"
+ [[ "$name" == "@" ]] && continue
+ umount "/mnt$mountpoint" 2>/dev/null || true
+ done
+
+ # Unmount root last
+ umount /mnt 2>/dev/null || true
+
+ info "Btrfs cleanup complete."
+}
diff --git a/custom/lib/disk.sh b/custom/lib/disk.sh
index fa3dbd2..38c6dd9 100644
--- a/custom/lib/disk.sh
+++ b/custom/lib/disk.sh
@@ -8,10 +8,17 @@
# Partition a single disk for ZFS/Btrfs installation
# Creates: EFI partition (512M) + root partition (rest)
+# Uses global FILESYSTEM variable to determine partition type
partition_disk() {
local disk="$1"
local efi_size="${2:-512M}"
+ # Determine root partition type based on filesystem
+ local root_type="BF00" # ZFS (Solaris root)
+ if [[ "$FILESYSTEM" == "btrfs" ]]; then
+ root_type="8300" # Linux filesystem
+ fi
+
info "Partitioning $disk..."
# Wipe existing partition table
@@ -20,8 +27,8 @@ partition_disk() {
# Create EFI partition (512M, type EF00)
sgdisk -n 1:0:+${efi_size} -t 1:EF00 -c 1:"EFI" "$disk" || error "Failed to create EFI partition on $disk"
- # Create root partition (rest of disk, type BF00 for ZFS or 8300 for Linux)
- sgdisk -n 2:0:0 -t 2:BF00 -c 2:"ROOT" "$disk" || error "Failed to create root partition on $disk"
+ # Create root partition (rest of disk)
+ sgdisk -n 2:0:0 -t 2:$root_type -c 2:"ROOT" "$disk" || error "Failed to create root partition on $disk"
# Notify kernel of partition changes
partprobe "$disk" 2>/dev/null || true
diff --git a/docs/PLAN-archangel-btrfs.org b/docs/PLAN-archangel-btrfs.org
index ea39bf6..9d91db7 100644
--- a/docs/PLAN-archangel-btrfs.org
+++ b/docs/PLAN-archangel-btrfs.org
@@ -98,7 +98,14 @@ BTRFS_OPTS="noatime,compress=zstd,space_cache=v2,discard=async"
- [ ] Verify appears in snapper list
- [ ] Verify appears in GRUB menu
-** 2.7 LUKS encryption (optional)
+** 2.7 Test basic btrfs (before encryption)
+- [ ] VM test: single-disk btrfs install
+- [ ] Verify subvolumes created correctly
+- [ ] Verify GRUB boots and shows snapshots
+- [ ] Verify snapper works
+- [ ] Verify genesis snapshot exists
+
+** 2.8 LUKS encryption (after basic btrfs works)
- [ ] Add encryption prompt (yes/no)
- [ ] Create LUKS container on root partition
- [ ] Configure crypttab
@@ -107,20 +114,31 @@ BTRFS_OPTS="noatime,compress=zstd,space_cache=v2,discard=async"
* Phase 3: Multi-disk Btrfs
-Goal: Mirror support for btrfs.
+Goal: Full multi-disk support for btrfs (matching ZFS capabilities).
-** 3.1 Btrfs RAID1 creation
-- [ ] Detect multi-disk selection
-- [ ] Create raid1 volume: mkfs.btrfs -d raid1 -m raid1 /dev/sdX /dev/sdY
-- [ ] Handle 2+ disk configurations
+** 3.1 RAID level support
+- [ ] Stripe (raid0): mkfs.btrfs -d raid0 -m raid0
+- [ ] Mirror (raid1): mkfs.btrfs -d raid1 -m raid1
+- [ ] raid10: mkfs.btrfs -d raid10 -m raid10 (4+ disks)
+- [ ] raid5: mkfs.btrfs -d raid5 -m raid5 (3+ disks, warn: unstable)
+- [ ] raid6: mkfs.btrfs -d raid6 -m raid6 (4+ disks, warn: unstable)
+- [ ] Detect multi-disk selection and offer appropriate levels
+- [ ] Handle mixed disk sizes gracefully
-** 3.2 EFI redundancy
+** 3.2 Encryption + multi-disk
+- [ ] LUKS on each disk before btrfs
+- [ ] crypttab entries for all disks
+- [ ] Test unlock sequence at boot
+- [ ] Single passphrase unlocks all (keyfile approach)
+
+** 3.3 EFI redundancy
- [ ] Create EFI partition on all disks
- [ ] Install GRUB to all EFI partitions
- [ ] Create boot entries for each disk
-** 3.3 Degraded boot support
+** 3.4 Degraded boot support
- [ ] Add degraded mount option for emergency
+- [ ] Kernel param: rootflags=degraded
- [ ] Document recovery procedure
* Phase 4: Testing Infrastructure
diff --git a/docs/session-context.org b/docs/session-context.org
index f441e89..66a1ae0 100644
--- a/docs/session-context.org
+++ b/docs/session-context.org
@@ -11,67 +11,52 @@
- Checked for conflicts: pwnerfly/Archangel is dead (2020, 0 stars, no license)
- Name is clear for use
-** Work Completed
-
-*** 1. Btrfs Implementation Planning
-- Created docs/PLAN-archangel-btrfs.org with 6-phase implementation
-- Expanded testing validation checks in research doc
-- Decided: snapper for snapshots, GRUB for btrfs boot
-
-*** 2. Phase 1: Refactor (COMPLETE)
-**** Phase 1.1: lib/ Structure
-Created modular library structure:
-- [X] custom/lib/common.sh - output, validation, fzf prompts, filesystem selection
-- [X] custom/lib/config.sh - argument parsing, config loading
-- [X] custom/lib/disk.sh - partitioning, disk selection
-- [X] custom/lib/zfs.sh - ZFS pool, datasets, services
-
-**** Phase 1.4: Filesystem Selection
-- [X] Added FILESYSTEM variable (zfs/btrfs)
-- [X] Added select_filesystem() with fzf prompt
-- [X] Btrfs selection shows "not yet implemented"
-- [X] Config file supports FILESYSTEM option
+*** Btrfs Implementation Approach
+- Phase 2: Single-disk btrfs, no encryption (test first)
+- Phase 2.7: Test basic btrfs before adding encryption
+- Phase 2.8: LUKS encryption after basic btrfs works
+- Phase 3: Multi-disk (stripe, mirror, raidX) + encrypted/unencrypted
-**** Phase 1.5: Rename to archangel
-- [X] Renamed install-archzfs → archangel
-- [X] Updated build.sh references
-- [X] Updated config example to archangel.conf.example
-- [X] Updated script headers
+*** Partition Type Handling
+- disk.sh checks global FILESYSTEM variable
+- ZFS: BF00 (Solaris root)
+- Btrfs: 8300 (Linux filesystem)
-*** 3. Bug Fix: set -e compatibility
-Found and fixed critical bug during VM testing:
-- [[ condition ]] && error pattern fails with set -e
-- Fixed by converting to if/then/fi pattern
-
-*** 4. VM Test PASSED
-Full end-to-end test:
-- ISO built with lib/ structure
-- Unattended install completed
-- ZFSBootMenu boots correctly
-- Genesis snapshots created
-- System fully functional
-
-** Commits This Session (11 total)
-- 94c2f15: Add archsetup --chroot task
-- 49a8b2e: Add btrfs implementation plan
-- d8eb81a: Expand testing validation checks
-- 15ac415: Phase 1.1 - Create lib/ directory structure
-- 498ab4d: Fix build.sh to include lib/ in ISO
-- c74b1d7: Fix set -e compatibility in lib functions
-- 0f56f1f: Update session context
-- 7cfdc69: Phase 1.1 complete: VM test passed
-- b8973f3: Phase 1.4 - Add filesystem selection prompt
-- 18c07ee: Phase 1.5 - Rename to archangel
-
-** Phase 1 Status: COMPLETE
+** Work Completed
-** Next Steps (Phase 2: Btrfs Support)
-1. Create lib/btrfs.sh with btrfs functions
-2. Implement subvolume creation
-3. Implement snapper configuration
-4. Implement GRUB + grub-btrfs
-5. Test btrfs installation
+*** 1. Phase 1: Refactor (COMPLETE)
+- [X] lib/common.sh, config.sh, disk.sh, zfs.sh created
+- [X] Filesystem selection prompt
+- [X] Renamed to archangel
+- [X] VM test passed
+
+*** 2. Phase 2: Btrfs Support (IN PROGRESS)
+**** Phase 2.1: lib/btrfs.sh (COMPLETE)
+- [X] Created lib/btrfs.sh with full implementation
+- [X] BTRFS_OPTS: noatime,compress=zstd,space_cache=v2,discard=async
+- [X] 10 subvolumes matching ZFS dataset layout
+- [X] Mount functions with proper options
+- [X] fstab generation (subvol= NOT subvolid!)
+- [X] Snapper configuration (timeline policy)
+- [X] GRUB + grub-btrfs configuration
+- [X] Genesis snapshot via snapper
+
+**** Updated Files
+- [X] disk.sh - filesystem-aware partition type
+- [X] archangel - sources btrfs.sh, install_btrfs() path
+- [X] build.sh - includes lib/btrfs.sh permissions
+- [X] PLAN-archangel-btrfs.org - added Phase 2.7/2.8
+
+**** Syntax Checks
+- [X] All lib/*.sh pass bash -n
+- [X] archangel passes bash -n
+- [X] All btrfs functions defined correctly
+
+** Next Steps
+1. Commit Phase 2.1 implementation
+2. Build ISO
+3. VM test btrfs installation path
** Notes
- Craig on remote console: 30 lines tall, ~145 columns wide
-- Craig stepped away ~17:23, working autonomously
+- Testing approach: syntax first, then full VM test