Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Phase 410 — install/use onix-busybox in the image

ItemValue
Commandmake phase 410
Underlying make target/scriptvm/phase4/materialize-etc.sh --busybox-stone
Reads package repoartifacts/onix-local-repo/stone.index
Installs package payload fromonix-busybox
Mutates disk/image?Yes, artifacts/onix-image/onix.raw
Boots QEMU?No
Main proofThe boot image now uses the locally built onix-busybox stone for /usr/bin/busybox and the /bin compatibility command links.

Why this phase exists

Phase 409 built the first replacement system package:

artifacts/onix-stones/onix-busybox-...stone
artifacts/onix-local-repo/stone.index

That was only half of the story.

After Phase 409, the package existed, but the boot image still used the older bootstrap BusyBox copied from Nix during Phases 403-406.

Phase 410 is the handoff:

local moss repo
      |
      v
onix-busybox stone
      |
      v
image /usr/bin/busybox
      |
      v
/bin compatibility links used by early bootstrap scripts

This matters because BusyBox is not a user toolbox.

BusyBox is base system machinery:

  • /bin/sh runs bootstrap scripts.
  • /bin/ifconfig and /bin/route bring up the first network proof.
  • /bin/nc runs the temporary TCP inspection listener.
  • /bin/netstat helps the SSH and remote-inspection status checks.
  • /bin/ls, /bin/cat, /bin/ps, and friends are the tiny repair toolbox.

So BusyBox belongs in the machine plane:

machine-plane software = moss/.stone packages
user toolbox software  = Nix

Phase 410 moves the active command path in that direction.

The basic Linux idea: root tree and command lookup

When the kernel boots, it eventually mounts the real root filesystem at:

/

That mounted filesystem is the running machine’s root tree.

Every absolute path starts there:

/usr/bin/busybox
/bin/sh
/etc/passwd
/usr/lib/systemd/systemd
/persist/home

When a script says:

/bin/sh /usr/lib/onix/bootstrap-network-up

Linux does not search randomly. It asks the filesystem:

Does /bin/sh exist?
Is it executable?
If it is a symlink, where does it point?
Can the final executable be loaded?

That is why symlinks are important in this phase.

BusyBox is one binary with many personalities.

The real executable is:

/usr/bin/busybox

It knows many applets:

sh
ls
cat
mount
ifconfig
nc
netstat

The common layout is:

/usr/bin/sh  -> busybox
/usr/bin/ls  -> busybox
/usr/bin/cat -> busybox

When Linux executes /usr/bin/ls, it actually starts busybox, but BusyBox sees that it was launched with the name ls, so it runs the ls applet.

This gives a tiny system many basic commands without shipping many separate programs.

Why the stone owns /usr/bin, not /bin

The onix-busybox stone owns:

/usr/bin/busybox
/usr/bin/sh
/usr/bin/ifconfig
/usr/bin/nc
/usr/share/onix/packages/onix-busybox.applets
/usr/share/onix/packages/onix-busybox.md

It does not own /bin.

That is deliberate.

During Phase 409 we learned that boulder/moss currently treat package payloads as /usr-centric. Non-/usr payload paths are not a good package ownership target yet.

So Phase 410 separates two ideas:

package ownership      = /usr/bin/...
image compatibility    = /bin/...

The package owns /usr/bin.

The image keeps one of two compatibility layouts.

If the root tree already uses merged /usr, then /bin itself points at usr/bin:

/bin -> usr/bin

In that layout, /bin/sh and /usr/bin/sh are the same path through the symlinked directory.

If the image has a real /bin directory instead, Phase 410 creates explicit compatibility links:

/bin/busybox -> ../usr/bin/busybox
/bin/sh      -> busybox
/bin/nc      -> busybox
/bin/ifconfig -> busybox

Both layouts keep the package model honest while letting older bootstrap scripts keep using /bin/sh, /bin/nc, and similar paths.

Why Phase 410 installs through a scratch moss target first

There is an important safety detail here.

The boot image already has a root tree assembled from earlier phases. It also has hand-written bootstrap files and systemd units.

A future ONIX image should be fully moss-managed, but we are not completely there yet.

If Phase 410 asked moss to install directly into the image root, moss might also write or rewrite package-manager state in ways that deserve their own careful phase.

So this phase does a safer two-step flow:

1. Use host moss to install onix-busybox into a disposable scratch target.
2. Copy only the verified package payload from that scratch target into the image.

The scratch target lives under:

artifacts/onix-phase4-work/busybox-install-target

That means Phase 410 still proves:

moss can consume the local repo and materialize onix-busybox

but it avoids pretending the whole image is already a final moss-managed system.

That full system-state integration belongs in later phases.

What the script does

Run:

make phase 410

The target calls:

vm/phase4/materialize-etc.sh --busybox-stone

The script:

  1. Attaches artifacts/onix-image/onix.raw through a loop device.

  2. Mounts the onix-root partition.

  3. Mounts the real ONIX-PERSIST partition under /persist.

  4. Checks that earlier bootstrap files from Phases 403-406 exist.

  5. Checks that the local repo index exists:

    artifacts/onix-local-repo/stone.index
    
  6. Uses host Moss from:

    artifacts/host-tools/bin/moss
    
  7. Adds the local repo to a disposable moss root.

  8. Installs onix-busybox into a scratch target.

  9. Verifies the scratch install:

    • /usr/bin/busybox exists and runs,
    • the binary has no dynamic interpreter,
    • required applets exist,
    • package notes exist.
  10. Copies the verified package payload into the image root.

  11. Preserves the image’s existing /bin policy:

    • if /bin -> usr/bin, applets resolve through /usr/bin;
    • otherwise explicit /bin/<applet> compatibility links are created.
  12. Rewrites the bootstrap serial unit to run:

    ExecStart=/usr/bin/busybox sh /usr/lib/onix/bootstrap-serial-shell
    
  13. Writes the proof note:

    /usr/share/onix/bootstrap/busybox-stone.txt
    
  14. Verifies the final image state.

What changes inside the image

After this phase, the image should contain:

/usr/bin/busybox
/usr/bin/sh -> busybox
/usr/bin/nc -> busybox
/usr/share/onix/packages/onix-busybox.applets
/usr/share/onix/packages/onix-busybox.md
/usr/share/onix/bootstrap/busybox-stone.txt

And the image compatibility path should resolve through either merged /usr:

/bin -> usr/bin
/bin/sh -> /usr/bin/sh -> busybox

or explicit compatibility links:

/bin/busybox -> ../usr/bin/busybox
/bin/sh      -> busybox
/bin/nc      -> busybox
/bin/netstat -> busybox

The bootstrap serial systemd unit should no longer execute the Nix BusyBox path.

It should execute:

/usr/bin/busybox

What does not change yet

This phase does not delete the old Nix BusyBox closure.

That sounds annoying, but it is intentional.

Deleting old payloads is a different kind of proof. We should only delete them after we have booted with the replacement and proved that the shell, network, remote inspection, and SSH paths still work.

So the truth after Phase 410 is:

active command path = onix-busybox stone
old Nix closure     = may still be present on disk

The later audit phase will remove or fail on leftover Nix-sourced machine-plane payloads.

Expected output

You should see the script say that it is installing from the local repo:

==> installing and activating onix-busybox from the local Phase 4 repo
==> materializing onix-busybox from local moss repo into a scratch target

Then it should copy the package payload and create compatibility links:

stone    : onix-busybox installed under /usr/bin
compat  : /bin -> usr/bin; applets resolve through /usr/bin

If the image does not use merged /usr, the compatibility line will instead show explicit /bin applet links.

The important success status is:

==> success
status: onix-busybox stone is installed and active for /bin compatibility links

How to inspect it manually

Phase 410 itself does not boot QEMU.

It mutates the image and prints a preview.

If you want to inspect the mounted result while debugging, use the script output first. It prints paths like:

/usr/bin/busybox
/bin -> usr/bin
/bin/sh -> busybox

Do not manually mount the image unless the scripts fail and we are debugging carefully. Manual mounts are easy to leave stale, and stale loop devices can confuse later phase runs.

Use:

make cleanup

if a phase is interrupted.

How this connects to the next phase

Phase 410 is a disk mutation proof.

It does not prove that the booted machine still works.

The next phase should boot the image and re-run the important behavioral checks:

serial shell
network status
remote inspection
SSH

That matters because filesystem verification can only prove paths exist.

Boot verification proves the running system can actually execute those paths.

In short:

409 = build package
410 = install/use package in image
411 = boot and prove behavior still works