make aroot builds a SchFS root from Alpine's minirootfs, the packages ports/alpine/world lists, and SchOS itself as the signed apk package schos-base, in its own repository inside the root. apk add installs from Alpine; apk upgrade updates both. Booted: zsh is Alpine's, apk update sees 28669 packages, apk add htop works, and so does xorg-server. world.lock pins every package with its sha256; a build fetches only what dist/alpine/ lacks and never looks for newer versions. make alpine-lock is the one step that does. Alpine's zsh, busybox commands and hwdata replace SchOS's copies; SchOS keeps its own tools, toybox's other commands, and static mksh, which schinit's recovery shell now tries first. Also: the dependency-file include matched Alpine's usr/lib/sysctl.d, a directory, and stopped every make. See docs/plan/alpine.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
3.3 KiB
apk: Alpine's packages on SchOS
Alpine is musl with a different init, and SchOS is musl with a different kernel. Alpine's binaries run on SchOS unmodified: its dynamic linker, its busybox, and apk itself, fetching over TLS through SchOS's network stack. So instead of porting programs one at a time, SchOS can install them.
The model
The root filesystem is an apk-managed root:
| Part | Where it comes from |
|---|---|
| musl, busybox, apk-tools, alpine-keys, CA certificates | Alpine's minirootfs (ports/alpine) |
what ports/alpine/world lists (zsh, terminfo, ...) |
Alpine's packages, pinned in world.lock |
| schinit, its jobs, SchOS's tools, toybox, mksh, configuration | schos-base, an apk package the build makes from sysroot/ |
apk add installs anything from Alpine's main and community repositories.
apk upgrade updates Alpine's packages, and schos-base from the SchOS
repository at /var/lib/schos/repo.
PID 1 is still schinit. Alpine's OpenRC is not installed, and packages that ship OpenRC services install them where nothing reads them.
Who owns what
Where Alpine and SchOS both have a program, Alpine's wins, and SchOS keeps
only what is its own (see tools/posix/mkaroot.sh):
/bin/sh,cat,sed,findand the rest are busybox. Alpine's package scripts are written against busybox.- zsh is Alpine's. SchOS keeps its
zshrcandzshenv(replaces=zsh). /etc/os-releaseand/etc/motdare SchOS's (replaces=).passwd,groupandprofileare Alpine's. schos-base's post-install sets root's shell to zsh, and SchOS's profile is/etc/profile.d/schos.sh.- mksh is
/bin/mksh. schinit's recovery shell looks for it first because it is static: a broken musl cannot take recovery down with it.
Building
make aroot build/aroot.img: the root, as a SchFS volume
make qemu-aroot boot it
make alpine-lock re-resolve world against Alpine (needs the network)
Only alpine-lock asks Alpine what is current. A normal build installs
exactly what world.lock names: files in dist/alpine/, fetched once and
checked against the lock's sha256, and against Alpine's signatures by apk.
schos-base and its repository index are signed with a key made on the first
build (build/apk-keys/, never committed). The root trusts it beside
Alpine's keys.
Kernel work this needed
All of it found by running apk:
- TCP receive window: it reopened before the reader drained, so lwIP refused data and the sender waited on retransmission timers (5 KB/s). It now reopens on read, with a 32-segment window.
- mmap address reuse: freed ranges were never reused, so musl's malloc used up the 256 mapping records with 780 MB of RAM free.
- unlinkat / renameat: bare
-1, read as EPERM, where apk expects ENOENT; renameat could not replace its target, and wrote v1 dirents into SchFS. #!scripts in execve, and ENOEXEC: apk runs triggers directly.- chroot, and mounting devtmpfs and proc more than once.
Next
- The live ISO and USB stick are still the ramdisk root. They need the apk root on the stick itself, or an installer that writes it to a disk.
- Xorg from apk (
xorg-server xf86-video-fbdev xf86-input-evdev) instead of the hand port in xorg.md. The packages install; running them is the next test.