Files
fruix/docs/reports/phase18-installer-environment-freebsd.md

6.3 KiB

Phase 18.2: minimal Fruix-managed installer environment on FreeBSD

Date: 2026-04-04

Goal

Phase 18.2 builds on the Phase 18.1 host-driven install primitive.

The goal here is not a polished live installer. The goal is a small Fruix-managed environment that can:

  • boot as its own Fruix system,
  • carry a selected target Fruix system closure and rootfs payload,
  • install that target system onto a second disk from inside the booted environment,
  • and leave the installed target bootable.

Implementation

New installer-environment API

Added in modules/fruix/system/freebsd.scm:

  • installer-operating-system
  • operating-system-installer-image-spec
  • materialize-installer-image

The installer environment is derived from the selected target operating system, but with installer-specific behavior:

  • host name defaults to:
    • <target-host-name>-installer
  • init mode is kept on the currently most stable installer path:
    • freebsd-init+rc.d-shepherd
  • the installer image root label is distinct:
    • fruix-installer-root
  • sshd is enabled for operator/debug access
  • installer accounts needed for SSH/DHCP are ensured if absent:
    • sshd
    • _dhcp

Bootable installer image contents

materialize-installer-image now produces a bootable image that contains:

  • the installer system closure and its runtime store closure
  • the selected target system closure
  • the selected target system's referenced store items
  • a prebuilt target rootfs tree staged under:
    • /var/lib/fruix/installer/target-rootfs
  • installer plan/state files under:
    • /var/lib/fruix/installer
  • installer helper scripts:
    • /usr/local/libexec/fruix-installer-run
    • /usr/local/etc/rc.d/fruix-installer

The booted installer environment runs a background rc.d job that:

  • partitions the selected target disk
  • creates EFI + UFS filesystems
  • copies the staged target rootfs onto the target
  • copies only the target system's required store items into the target /frx/store
  • installs the target's loader.efi
  • writes /var/lib/fruix/install.scm on the target
  • records installer state in:
    • /var/lib/fruix/installer/state
  • logs to:
    • /var/log/fruix-installer.log

New CLI action

Added in scripts/fruix.scm:

  • fruix system installer

Added option:

  • --install-target-device DEVICE

This action materializes a bootable installer image in /frx/store and emits metadata for:

  • installer image paths
  • installer closure path
  • target closure path
  • target install device
  • installer state/log paths
  • declared/materialized FreeBSD source metadata
  • target/native/runtime store metadata

FreeBSD virtio target-device detail

A practical detail surfaced during validation:

  • the correct FreeBSD virtio block device node for the second QEMU disk is:
    • /dev/vtbd1

The earlier Linux-flavored guess:

  • /dev/vtblk1

was wrong for the actual FreeBSD device node namespace in this environment.

The installer defaults were updated accordingly.

Small image-builder correctness fix

While doing this work I also fixed materialize-bhyve-image so its generated UFS filesystem label respects the requested:

  • root-partition-label

instead of always hardcoding:

  • fruix-root

This matters for the installer image because it needs a distinct root label while the target disk still uses the normal target label.

Validation

Added validation artifacts:

  • tests/system/phase18-installer-target-operating-system.scm.in
  • tests/system/run-phase18-installer-environment.sh

Passing validations:

  • PASS phase18-installer-environment
  • regression re-check:
    • PASS phase18-system-install
  • regression re-check:
    • PASS phase17-source-revisions-qemu

Validated installer-environment result:

installer_image_store_path=/frx/store/fb038dbf5dac2ad1bb767a264d3a268915f489b936dc5dd32425645102d3da48-fruix-installer-image-fruix-freebsd-installer
installer_disk_image=/frx/store/fb038dbf5dac2ad1bb767a264d3a268915f489b936dc5dd32425645102d3da48-fruix-installer-image-fruix-freebsd-installer/disk.img
installer_disk_capacity=16g
installer_root_size=14g
target_disk_capacity=12g
install_target_device=/dev/vtbd1
installer_closure_path=/frx/store/ea821f20b579684877fdc86a2a1e80485cf2b12d9d32f74f42e368d738c2ad4d-fruix-system-fruix-freebsd-installer
target_closure_path=/frx/store/7ee225db532b6973e385f8507d2d61aec3cd3aeb0864f983c2ae4b6e149ef3b0-fruix-system-fruix-freebsd
freebsd_source_kind=git
freebsd_source_ref=stable/15
freebsd_source_commit=332708a606f6bf0841c1d4a74c0d067f5640fe89
materialized_source_store=/frx/store/7563df2714ae7fa9bd40b83c74512ffe2cb2ad91b297915591b55c76edbb2fcb-freebsd-source-stable15-installer-target-source
installer_state=done
installer_sshd_status=running
target_esp_fstype=msdosfs
target_root_fstype=ufs
target_shepherd_status=running
target_sshd_status=running
installer_environment_boot=ok
installer_environment_install=ok
installed_target_boot=ok

The harness verified all of the following:

  1. fruix system installer produces a bootable installer image in /frx/store
  2. validation boots a workdir copy of that installer disk image so the store artifact itself is not mutated during the boot/install run
  3. the installer environment boots successfully under QEMU/UEFI/TCG
  4. the installer environment becomes reachable over SSH
  5. /run/current-system inside the installer environment points at the installer closure
  6. the installer rc.d job reaches:
    • state=done
  7. the installer log records:
    • fruix-installer:done
  8. the target raw disk is transformed into a valid GPT-installed Fruix target with:
    • EFI filesystem: msdosfs
    • root filesystem: ufs
    • EFI/BOOT/BOOTX64.EFI present
    • /var/lib/fruix/install.scm present
  9. the installed target then boots successfully as its own Fruix system under QEMU/UEFI/TCG
  10. after target boot:
  • /run/current-system points at the target closure
  • /usr/local/etc/rc.d/fruix-shepherd onestatus reports running
  • sshd is running
  • activation completed successfully

Result

Phase 18.2 is complete.

Fruix now has a real installer substrate on FreeBSD:

  • a bootable Fruix-managed installer image
  • a target closure bundled inside that installer environment
  • in-guest non-interactive installation onto a second disk
  • validated boot of the installed result

The next step is Phase 18.3:

  • produce a bootable installer ISO for UEFI systems, rather than only a disk-image-style installer environment.