Implement package installation in chroot environment to replace
void-installer dependency. Module installs minimal base system:
- Base-System: base-system, linux, linux-firmware, grub, cryptsetup, dracut
- Network: dhcpcd, iproute2, iputils
- Tools: vim, nano, sudo
Decision: Install conservative package set by default.
Base packages are sufficient for bootable CLI system with network.
Desktop environments can be added later via config file support.
Alternative considered: Interactive package selection rejected
(violates CLI-only requirement from requirements document).
Trade-off: Fixed package list means less flexibility but simpler
initial implementation. Future config file support will allow
customization.
Validation: Package verification after installation ensures
critical packages are present before continuing.
Add cleanup for bind mounts (/dev, /proc, /sys, /run) created
during post-install phase. Without this, failures in post-install
leave bind mounts active, preventing subsequent cleanup of the
main filesystem mounts.
Clean bind mounts first (innermost to outermost), then regular
mounts, then LUKS mapping to ensure proper teardown order.
Decision: Check each bind mount individually rather than relying
on umount -R to handle everything, for better error reporting and
partial cleanup capability.
Context: Bind mounts are only created if post-install phase is
reached, but rollback must handle cleanup from any failure point.
Add three critical improvements to post-install phase:
1. Cleanup trap for bind mounts: Ensure /dev, /proc, /sys, /run
are unmounted even if chroot script fails. Prevents orphaned
mounts blocking cleanup.
2. Fallocate fallback: Use dd as fallback if fallocate fails
(can happen on some filesystems or with insufficient space).
Includes intelligent size conversion and progress display.
3. Progress messages: Add informative echo statements before
long-running operations (xbps-reconfigure, grub-install,
grub-mkconfig) so users know the system is working.
Decision: Use trap EXIT instead of manual cleanup to guarantee
execution on both success and error paths. Remove redundant
explicit cleanup call.
Trade-offs: dd fallback is slower but ensures swap file creation
succeeds. Progress messages add noise but significantly improve
UX during multi-minute operations.
Add verification that critical mounts (root and ESP) are still
intact after void-installer exits. Catches cases where installer
accidentally reformats filesystems despite instructions.
Fail fast with clear error message if mounts disappeared, rather
than proceeding to post-install and encountering cryptic errors.
Decision: Check mounts immediately after installer rather than
during post-install to provide clear failure point and message.
Alternative considered: Monitor installer process to prevent
reformatting, rejected as too invasive and complex.
Add trap to ensure temp mount is cleaned up if btrfs subvolume
creation fails. Without this, failures leave mounted filesystems
and orphaned directories, blocking retry attempts.
Use mountpoint -q for robust mount detection before cleanup.
Decision: Use local trap within format_filesystems to avoid
interfering with main error handler. Reset trap after successful
completion to prevent double cleanup.
Trade-off: Slightly more complex code vs guaranteed cleanup on
error paths.
Add validate_size() function to check format of user-provided
size inputs (ESP_SIZE, ROOT_END, SWAP_SIZE) before they reach
partitioning tools. Prevents cryptic parted errors from invalid
formats like "abc" or "1X".
Improve SWAP_SIZE normalization to handle all zero variants
(0, 0G, 0GB, 0GiB, 0M, 0MB, 0MiB) consistently.
Decision: Validate at config phase rather than partition phase
to provide early, clear feedback. Use regex pattern that matches
parted's expected format (number + optional unit or percentage).
Alternative considered: Let parted handle validation, rejected
because error messages would be less user-friendly.
Export ESP_PART and ROOT_PART variables to ensure they are
available in all subsequent modules (encryption, filesystems,
postinstall). While sourcing makes them accessible, explicit
exports clarify the sharing model and prevent potential issues
in different shell contexts.
Decision: Use explicit export instead of relying on implicit
variable propagation through source to make dependencies clear.
Add literate programming phase 1 documentation for:
- logging.sh: transparency and auditability during operations
- rollback.sh: cleanup strategy after failures
Decision: Plain text logs for readability over structured JSON.
Log destination is /tmp/void-wrapper-YYYY-MM-DD-HHMMSS.log to
avoid conflicts in multi-run sessions. Logs remain ephemeral
in live environment, not copied to target system.
Decision: Three log levels (INFO, WARN, ERROR) with clear
separation between stdout (user-facing) and log file (detailed
trace). Secret masking prevents passphrase exposure.
Decision: Best-effort rollback limited to reversible operations.
Unmount filesystems and close LUKS mappings, but never revert
partitioning or formatting (irreversible without data loss).
Only cleanup after explicit user confirmation.
Rationale: Full automatic rollback rejected due to complexity
and risk. Partial cleanup with clear manual recovery instructions
is safer and more transparent. Track failed phase to provide
targeted recovery advice.
Open questions for phase 2:
- Support verbose/debug mode beyond standard levels?
- Display log path at end for manual review?
- Handle log rotation in multi-run sessions?
Add literate programming phase 1 documentation for:
- installer.sh: handoff to official Void installer
- postinstall.sh: boot configuration for encrypted system
Decision: Keep official installer in the loop rather than
full automation. The installer handles package selection and
system configuration choices better than a custom script would.
Reduces maintenance burden significantly.
Decision: GRUB as default bootloader for wide Void support
without systemd dependencies. systemd-boot and rEFInd rejected
due to availability constraints. EFISTUB rejected due to manual
UEFI entry management overhead.
Technical details documented for post-install phase:
- dracut crypt module enables LUKS unlock in initramfs
- /etc/crypttab uses UUID references for device stability
- GRUB_ENABLE_CRYPTODISK=y enables GRUB LUKS unlock
- rd.luks.uuid kernel parameter tells dracut which container
- grub-install embeds cryptodisk, grub-mkconfig updates menu
Open questions preserved for phase 2 implementation:
- Should rescue initramfs be generated?
- Verify GRUB LUKS2 support before reboot?
- Document kernel update process for users?
Add literate programming phase 1 documentation for:
- partitioning.sh: UEFI layout with ESP and encrypted root
- encryption.sh: LUKS encryption strategy and key handling
- filesystems.sh: filesystem choices and swap configuration
- mounts.sh: mount tree preparation for installer handoff
Decision: Swap file instead of swap partition for automatic
encryption and flexibility. Swap partition would require either
a second LUKS container (two passphrases at boot), unencrypted
swap (security risk), or LVM (out of scope).
Decision: /boot inside encrypted root for simplicity. GRUB
unlocks LUKS once, kernel and initramfs are protected. ESP
remains unencrypted per UEFI requirements.
Decision: Default to btrfs with explicit ext4 opt-in. Btrfs
provides snapshots and flexibility. Swap file on btrfs requires
No-COW subvolume to avoid corruption.
Trade-off: LUKS2 vs LUKS1. LUKS2 provides better security
features and tooling, but GRUB <2.06 may have incomplete
support. Users informed of potential boot issues with clear
recovery path rather than silent downgrade.
Add literate programming phase 1 documentation for:
- main.sh: wrapper orchestration and user journey
- config.sh: configuration management and defaults
- sanity.sh: preflight safety checks
Decision: UEFI-only support to reduce complexity. BIOS would
require separate /boot partition and additional testing burden
disproportionate to modern hardware usage.
Decision: LUKS2 as default encryption for improved security
tooling, with clear guidance for LUKS1 fallback if GRUB boot
fails. Auto-detection rejected due to version fragmentation.
Decision: Interactive configuration as default. Presets are
out of scope for phase 1 to keep the flow understandable.
The user journey documents the complete end-to-end flow from
live medium boot to first encrypted boot, establishing clear
handoff points between wrapper and installer.
Add comprehensive documentation for literate programming approach:
- Phase 1 guidelines focusing on why/what without implementation
- General literate programming principles for code documentation
- Project notes explaining wrapper script concept and strategy
Decision: Follow literate programming to make the wrapper
maintainable and educational. Comments tell the story, code
implements it. This foundation enables better collaboration
and knowledge transfer.
The notes.md establishes the core concept: a reproducible
wrapper around the Void installer that automates error-prone
LUKS encryption setup while keeping user control over system
configuration choices.