SchOS/docs/plan/alpine.md
Nexoniarz 3f8e5190aa build: the apk root is the only root
make qemu and make iso went on building sysroot/ as the root while only
make aroot built the apk one. Both now come from the apk root: a 1 GB
schfs.img for make qemu, and a 96 MB ramdisk for the ISO, 35 MB of it
the base system and the rest room for apk add on the live system.
sysroot/ is what schos-base is packaged from, not a root of its own.

hwdata leaves the ramdisk exclude list: it is Alpine's package now, and
a root missing files apk's database lists is one apk has to repair.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
2026-10-24 17:06:11 +02:00

77 lines
3.5 KiB
Markdown

# 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`, `find` and the rest are busybox. Alpine's package
scripts are written against busybox.
- zsh is Alpine's. SchOS keeps its `zshrc` and `zshenv` (`replaces=zsh`).
- `/etc/os-release` and `/etc/motd` are SchOS's (`replaces=`).
- `passwd`, `group` and `profile` are 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 qemu boots build/schfs.img, the root as a 1 GB SchFS disk
make iso the same root as the live system's 96 MB ramdisk
make alpine-lock re-resolve world against Alpine (needs the network)
It is the only root. sysroot/ is what schos-base is packaged from.
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 runs the apk root from RAM: `apk add` works, into 59 MB, and
is gone at reboot. Keeping packages needs an installer that writes the root
to a SATA or NVMe disk, and a kernel that finds its root there by the
SchFS GPT type rather than as IDE disk 1.
- Xorg from apk (`xorg-server xf86-video-fbdev xf86-input-evdev`) instead of
the hand port in [xorg.md](xorg.md). The packages install; running them is
the next test.