84 lines
3.6 KiB
Markdown
84 lines
3.6 KiB
Markdown
# World init
|
|
|
|
`/bin/init.wasm` owns unit policy. The host starts init without a conversation.
|
|
The host restarts init after an exit and kills its descendants before the next start.
|
|
|
|
Init reads persistent units from `/etc/systemd/system/*.service`.
|
|
It reads transient units from `/run/systemd/transient/*.service`.
|
|
The host mounts `/run` in memory, so transient units disappear after a host restart.
|
|
|
|
Unit files use `[Unit]`, `[Service]`, and `[Install]` sections.
|
|
Init supports dependency ordering, simple and oneshot services, environment variables, and restart policies.
|
|
The default start limit permits five starts within ten seconds.
|
|
A stop closes stdin. Init kills the process group after `TimeoutStopSec`, which defaults to ten seconds.
|
|
When init receives EOF, it stops dependents before prerequisites.
|
|
|
|
Enable records are files under `default.target.wants` or `multi-user.target.wants` in the persistent unit directory.
|
|
The `[Install]` section supplies `WantedBy` for `systemctl enable`.
|
|
Init observes VFS changes and applies unit edits without `daemon-reload`.
|
|
A change to a running unit's executable content restarts that unit.
|
|
Init resolves bare executable names through `PATH`, which defaults to `/usr/local/bin:/bin`.
|
|
Each directory tries the bare name before the `.wasm` suffix.
|
|
Init watches those candidate paths and compares the resolved executable's content hash.
|
|
After an overflow, init rescans definitions and executable hashes.
|
|
It restarts only units with a changed definition or executable.
|
|
Unrelated world writes do not enter these watcher queues.
|
|
Init and request clients block on pollables, with timers for lifecycle deadlines.
|
|
|
|
## Control protocol
|
|
|
|
The protocol uses UTF-8 JSON files. Writers create a temporary file, then rename it to the final path.
|
|
Each request uses a unique identifier.
|
|
|
|
1. The client watches `/run/systemd/replies/<id>` before it submits the request.
|
|
2. The client writes `/run/systemd/requests/<id>.json`.
|
|
3. Init reads the request and applies the action.
|
|
4. Init writes `/run/systemd/replies/<id>` and removes the request.
|
|
5. The client reads and removes the reply.
|
|
|
|
Request example:
|
|
|
|
```json
|
|
{"action":"start","unit":"example.service"}
|
|
```
|
|
|
|
Actions are `start`, `stop`, and `restart`.
|
|
A reply acknowledges the action. It does not imply that the service completed its start or stop.
|
|
The control tools then wait for the requested state. A failed start returns code 1.
|
|
|
|
Reply example:
|
|
|
|
```json
|
|
{"code":0,"text":""}
|
|
```
|
|
|
|
A missing unit returns code 5. An unknown action returns code 1.
|
|
Clients read `/run/systemd/state/<unit>` for the current state:
|
|
|
|
```json
|
|
{"state":"active","pid":42,"code":null}
|
|
```
|
|
|
|
States are `inactive`, `activating`, `active`, `deactivating`, and `failed`.
|
|
The `code` field records the most recent exit status.
|
|
`systemctl is-active` returns 3 for an inactive unit.
|
|
`systemctl is-failed` returns 0 for a failed unit and 1 otherwise.
|
|
`daemon-reload` returns 0 without an action.
|
|
|
|
## Journal
|
|
|
|
Init drains each unit's stdout and stderr into `/var/log/journal/<unit>.log`.
|
|
The cap is 1 MiB. Init keeps one rotated file with the `.1` suffix.
|
|
`journalctl -u <unit> -n <count>` prints the last lines.
|
|
`journalctl -f` observes the journal file and prints appended bytes.
|
|
|
|
## Process observation
|
|
|
|
`sausage-spawn` exposes `Watcher`, `ChangeKind`, and child exit pollables.
|
|
A watcher matches each supplied path and all its descendants.
|
|
Its pollable remains ready while changes remain pending.
|
|
`changes()` returns and clears the pending changes.
|
|
Each watcher filters paths before its independent queue holds at most 256 changes.
|
|
An `overflow` event requires a rescan.
|
|
Observers report successful VFS mutations, not direct host filesystem writes outside the VFS.
|