# zyginit

Init daemon and service supervisor for Zygaena/Hammerhead.

zyginit replaces SMF (Service Management Facility) with a single-process
service manager written in [Reef](https://www.leafscale.com). It uses
TOML service definitions, symlink-based enable/disable, and Hammerhead
process contracts for kernel-level service tracking.

## Components

| Binary | Path | Description |
|--------|------|-------------|
| `zyginit` | `/sbin/init` (kernel exec target on Hammerhead) | PID 1 init daemon and service supervisor |
| `zygctl` | `/sbin/zygctl` | Administrative CLI tool |
| `sysv-wrapper` | `/sbin/sysv-wrapper` (+ symlinks `halt`, `reboot`, `poweroff`, `telinit`) | Translates legacy commands to `zygctl` calls |

## Requirements

- Reef 0.4.0+ compiler (`reefc`)
- Clang or GCC (C compiler — for `helpers.c` and contract stubs on Linux)
- Hammerhead OS (for process contract support; Linux for development only)

## Building

### On Hammerhead (production)

```
gcc -c src/helpers.c -o build/helpers.o
reefc build -l contract --obj build/helpers.o
cd tools/zygctl && gcc -c src/symlink_wrapper.c -o build/symlink_wrapper.o && reefc build --obj build/symlink_wrapper.o
cd tools/sysv-wrapper && make
```

`helpers.o` is REQUIRED — it provides `zyginit_*` C wrappers (uadmin,
sync, fsync, utmpx writes, STREAMS push, system()) that the Reef code
calls via `extern "C"`. Without it the link fails on undefined refs.

### On Linux (development, contracts stubbed)

```
clang -c src/helpers.c -o build/helpers.o
clang -c src/contract_linux_stubs.c -o build/contract_linux_stubs.o
reefc build --obj build/helpers.o --obj build/contract_linux_stubs.o
cd tools/zygctl && clang -c src/symlink_wrapper.c -o build/symlink_wrapper.o && reefc build --obj build/symlink_wrapper.o
```

### Build output

```
build/zyginit                            # The init daemon
tools/zygctl/build/zygctl                # The admin CLI
tools/sysv-wrapper/sysv-wrapper          # The legacy-command shim
```

### Install on Hammerhead

```
cp build/zyginit /sbin/init
cp tools/zygctl/build/zygctl /sbin/zygctl
cd tools/sysv-wrapper && make install     # creates /sbin/halt, /sbin/reboot, /sbin/poweroff, /sbin/telinit
```

## Configuration

Service definitions are TOML files in `/etc/zyginit/`:

```
/etc/zyginit/
├── sshd.toml
├── cron.toml
├── syslog.toml
├── network.toml
├── network/
│   └── start.sh
├── filesystem.toml
├── filesystem/
│   └── start.sh
└── enabled.d/
    ├── sshd -> ../sshd.toml
    ├── cron -> ../cron.toml
    └── ...
```

Services are enabled by symlinks in `enabled.d/`. See the
[Administration Guide](docs/guide.md) for details.

### Example service definition

```toml
# /etc/zyginit/sshd.toml
[service]
name = "sshd"
description = "Secure Shell Daemon"
type = "daemon"

[exec]
start = "/usr/lib/ssh/sshd -D"

[runlevel]
mode = "multi"             # default — runs in multi-user only

[dependencies]
requires = ["network", "filesystem"]

[restart]
on = "failure"
delay = 5
max_retries = 3
```

The `[runlevel] mode` field accepts `"always"`, `"single"`, or `"multi"`
(default `"multi"`). Essential services that need to run in single-user
recovery mode (root-fs, devfs, filesystem, etc.) use `"always"`. The
recovery shell itself uses `"single"`.

## Usage

### Managing services

```
zygctl status              # Show all service states
zygctl status sshd         # Show one service
zygctl start sshd          # Start a service
zygctl stop sshd           # Stop a service
zygctl restart sshd        # Restart a service
zygctl enable sshd         # Enable at boot
zygctl disable sshd        # Disable at boot
zygctl reload              # Re-scan enabled.d for changes
zygctl log sshd            # Show service output log
zygctl list                # List all definitions
```

### Runlevel transitions and shutdown

```
zygctl single              # Transition to single-user (recovery) mode
zygctl multi               # Transition back to multi-user
zygctl halt                # Cleanly stop services + halt
zygctl reboot              # Cleanly stop services + reboot
zygctl poweroff            # Cleanly stop services + poweroff
```

The legacy commands work too via `/sbin/sysv-wrapper` symlinks:

```
init 0      → zygctl halt
init 5      → zygctl poweroff
init 6      → zygctl reboot
init s/S/1  → zygctl single
init 2/3/4  → zygctl multi
init q/Q    → zygctl reload
halt        → zygctl halt
reboot      → zygctl reboot
poweroff    → zygctl poweroff
telinit <N> → like init <N>
```

### Boot args

The kernel passes `boot-args` from the loader to `/sbin/init`. zyginit
honors `-s` for single-user boot:

```
# In /boot/loader.conf:
boot-args="-v -s"
```

### Testing without replacing PID 1

Run zyginit as a regular process with a custom config directory:

```
export ZYGINIT_CONFIG_DIR=/path/to/test/zyginit
export ZYGINIT_SOCKET=/tmp/zyginit.sock
./build/zyginit
```

Then use zygctl with the same socket:

```
ZYGINIT_SOCKET=/tmp/zyginit.sock ./tools/zygctl/build/zygctl status
```

## Documentation

- [Administration Guide](docs/guide.md) — Writing services, boot sequence, troubleshooting
- [Architecture and Design](docs/DESIGN.md) — Design decisions and rationale
- [Roadmap](ROADMAP.md) — Forward-looking plan with task checklists
- [Implementation Plan](docs/IMPLEMENTATION_PLAN.md) — Module-by-module technical details
- Man pages in `docs/man/`:
  - `zyginit(8)` — Init daemon
  - `zygctl(8)` — Admin CLI
  - `zyginit(5)` — Service definition format
- Example services in `services/examples/`

## Architecture

zyginit is a single-threaded process using `poll(2)` to monitor:

- **Process contracts** — Kernel-level service tracking (Hammerhead)
- **Signal pipe** — SIGCHLD, SIGTERM, SIGHUP handling
- **Unix socket** — `zygctl` command interface

At boot, service dependencies are resolved via topological sort into
parallel tiers. Services within a tier start concurrently.

### What zyginit does NOT do

- No XML parsing (that's the point of replacing SMF)
- No SQLite database
- No door-based IPC
- No multi-daemon architecture
- No 32-bit support (Hammerhead is 64-bit only)

## Project Layout

```
zyginit/
├── reef.toml                   # Reef project manifest
├── README.md                   # This file
├── ROADMAP.md                  # Forward-looking roadmap
├── CLAUDE.md                   # AI assistant context
├── src/
│   ├── main.reef               # Event loop, runlevel, shutdown
│   ├── config.reef             # TOML config parser (incl. [runlevel])
│   ├── depgraph.reef           # Dependency graph and topological sort
│   ├── contract.reef           # Hammerhead process contract FFI
│   ├── supervisor.reef         # Service lifecycle, restart, transitions
│   ├── socket.reef             # Unix domain socket server
│   ├── shutdown.reef           # uadmin / sync wrappers
│   ├── helpers.c               # C glue (uadmin, fsync, utmpx, ...)
│   └── contract_linux_stubs.c  # Linux dev stubs for libcontract
├── tools/
│   ├── zygctl/                 # Admin CLI (separate Reef project)
│   └── sysv-wrapper/           # Tiny C binary for /sbin/halt etc.
├── services/
│   ├── examples/               # Example TOML service definitions
│   └── hammerhead/             # Production boot chain for hh-prototest
├── docs/
│   ├── guide.md                # Administration guide
│   ├── DESIGN.md               # Architecture and design
│   ├── IMPLEMENTATION_PLAN.md
│   ├── superpowers/plans/      # Per-iter implementation plans
│   └── man/                    # Man pages (mdoc format)
├── tests/
│   └── integration/            # Integration test suite (run_tests.sh)
└── stub/                       # Original design stubs (reference)
```

## License

CDDL-1.0

## Author

Chris Tusa <chris.tusa@leafscale.com>
[Leafscale, LLC](https://www.leafscale.com)
