internal

package
v0.0.0-...-6cb71f3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 18, 2026 License: MIT Imports: 39 Imported by: 0

Documentation

Index

Constants

View Source
const ControlSocket = "/run/sv.sock"

ControlSocket is the Unix socket PID 1 serves for the `sv` service-control CLI. It is root-only (0600).

Variables

View Source
var DefaultReaper = NewReaper()

DefaultReaper is the process-wide reaper used by init's helpers (getty, ssh).

Functions

func ConfigureStaticNetwork

func ConfigureStaticNetwork(iface, ipCIDR, gateway string, dns []string) error

ConfigureStaticNetwork assigns a static address (CIDR, e.g. "192.0.2.10/24") to iface, optionally adds a default route via gateway, and writes the given DNS servers to /etc/resolv.conf. It is idempotent (replaces existing address and route), so it can be re-applied.

func ConfiguredConsoles

func ConfiguredConsoles(cfg *Config) []string

ConfiguredConsoles returns the ttys to run a console getty on. If rc.conf sets `CONSOLES` (whitespace-separated, e.g. "tty0 ttyAMA0"), that list is used verbatim. Otherwise the default is tty0 (the virtual console) plus whatever serial console the kernel was told to use on its cmdline (`console=`) — so a graphical console and a headless/serial deployment both get a login, and we use the arch's real serial device (ttyAMA0 on arm64, ttyS0 on amd64) rather than guessing from a static list (the 8250 driver pre-creates phantom /dev/ttyS0..3 nodes on arm64 that aren't real ports, so device-node existence can't tell a usable serial port from a stub — the kernel's own console= can).

func CreateDevices

func CreateDevices() error

func DHCPClient

func DHCPClient(ifname string) (*dhclient.Client, error)

func ErrInvalidCfgFile

func ErrInvalidCfgFile(cfgFile string) error

func ErrNotExists

func ErrNotExists(fieldName string) error

func ExitStatus

func ExitStatus(ws unix.WaitStatus) int

ExitStatus maps a wait status to a conventional process exit code.

func FormatUptime

func FormatUptime(d time.Duration) string

FormatUptime renders a duration compactly for status output: "5s", "4m12s", "1h03m", "2d04h". A non-positive duration (a service that isn't running) shows as "-".

func Gettys

func Gettys(ctx context.Context, ttys []string, persist bool)

Gettys spawns a getty on each named tty (e.g. "tty0", "ttyS0", "ttyAMA0") whose device node exists, so an explicitly-configured console with no node at all is skipped rather than left error-looping. If persist is true, each surviving getty is respawned when it exits.

func InterfaceUp

func InterfaceUp(ifname string) error

func Mkdev

func Mkdev(major, minor int) int

Mkdev is used to build the value of linux devices (in /dev/) which specifies major and minor number of the newly created device special file. Linux device nodes are a bit weird due to backwards compat with 16 bit device nodes. They are, from low to high: the lower 8 bits of the minor, then 12 bits of the major, then the top 12 bits of the minor.

func Mknod

func Mknod(path string, mode uint32, dev int) error

Mknod creates a filesystem node (file, device special file or named pipe) named path with attributes specified by mode and dev.

func NewSSHServer

func NewSSHServer(bind, keys string, opts ...option) (*server, error)

func ParseServiceConfigs

func ParseServiceConfigs(dir string) (map[ServiceType][]*Service, error)

Parses all the config in directory dir return a map of providers of ServiceTypes from that directory.

func RunReaper

func RunReaper()

RunReaper runs the DefaultReaper. Call it once, in a goroutine, from PID 1.

func ScanDevices

func ScanDevices(ctx context.Context) error

ScanDevices walks /sys/devices for the existing (cold-plugged) devices and populates /dev, the udev coldplug that has to finish before gettys start (they need their tty nodes). It dominated boot time as a single-threaded walk that read every `uevent` file in series, so this does it concurrently: collect the uevent paths (a cheap readdir-only pass), then read/parse them and mknod the nodes in a worker pool. The cost is the per-file sysfs reads, which are independent and syscall-bound, so overlapping them across CPUs roughly halves the phase. addDevice only ever touches distinct /dev paths and os.MkdirAll/ Mknod tolerate concurrency, so the parallelism is safe; the resulting set of nodes is identical to the serial scan.

func ServeControl

func ServeControl(sup *Supervisor) error

ServeControl creates the control socket and serves it in the background, dispatching requests to the supervisor. It returns once the listener is up.

func SetupFirewall

func SetupFirewall(sshPort uint16, containerBridge string) error

SetupFirewall installs a conservative baseline nftables policy: a single `inet gonix_filter` table with an input chain whose policy is drop, but which accepts loopback, established/related connections, SSH, ICMP/ICMPv6, and anything arriving on the container bridge (so box containers can still reach host services such as DNS). The forward and output paths are left untouched, so box's own NAT/forward rules keep working.

It is opt-in (init only calls it when configured) and the caller treats any error as non-fatal.

func SetupNetworkInterfaces

func SetupNetworkInterfaces() error

func StartSSHServer

func StartSSHServer(ctx context.Context)

func StartServices

func StartServices(providers map[ServiceType][]*Service)

StartServices starts every service, gating each on its declared Needs and only marking a service's Provides available once it has started successfully.

func WaitForCarrier

func WaitForCarrier(ifname string, timeout time.Duration) bool

WaitForCarrier blocks until the named interface reports link carrier (the NIC has finished negotiating a link), or timeout elapses. Emulated NICs that model real hardware — notably VirtualBox's e1000 — take a couple of seconds to bring the link up after the interface is administratively up, so starting a DHCP client immediately would fire its first DISCOVER into a dead link and (depending on the client) never recover. QEMU's virtio-net reports carrier instantly, so there this returns right away. A timeout is NOT fatal: callers proceed and let DHCP retry, so a genuinely link-less box still boots.

func WatchDevices

func WatchDevices(ctx context.Context) error

WatchDevices watches /sys for devices and populates /dev

func WithHostKeyFile

func WithHostKeyFile(fn string) option

Types

type Command

type Command string

func (Command) String

func (c Command) String() string

type Config

type Config struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

func NewConfig

func NewConfig(filename string) *Config

func (*Config) Load

func (cfg *Config) Load() error

func (*Config) ReadInt

func (cfg *Config) ReadInt(k string, def int) (int, error)

func (*Config) ReadString

func (cfg *Config) ReadString(k string, def string) (string, error)

func (*Config) Save

func (cfg *Config) Save() error

func (*Config) WriteInt

func (cfg *Config) WriteInt(k string, val int)

func (*Config) WriteString

func (cfg *Config) WriteString(k string, val string)

type ControlRequest

type ControlRequest struct {
	Action  string `json:"action"`            // status | start | stop | restart
	Service string `json:"service,omitempty"` // empty with status = all services
}

ControlRequest is one command from `sv` to the supervisor.

type ControlResponse

type ControlResponse struct {
	OK       bool            `json:"ok"`
	Error    string          `json:"error,omitempty"`
	Services []ServiceStatus `json:"services,omitempty"`
}

ControlResponse is the supervisor's reply.

type MountOption

type MountOption struct {
	Source string
	Target string
	Type   string
	Flag   uintptr
	Option string
}

type Reaper

type Reaper struct {
	// contains filtered or unexported fields
}

As PID 1, init must reap every child that exits — both processes it started (gettys, ssh session commands, services) and orphans reparented to it. The naive approach (a goroutine looping on wait4(-1)) races os/exec's own cmd.Wait(): whichever calls wait4 first gets the status, so cmd.Wait() often returns ECHILD ("no child processes") and exit codes are lost.

The Reaper makes init the single owner of child reaping. Callers that spawn a child register its PID with Wait() and receive its exit status on the returned channel; orphans (no registered waiter) are reaped and discarded. Nothing else in init may call wait4/cmd.Wait().

func NewReaper

func NewReaper() *Reaper

func (*Reaper) Run

func (r *Reaper) Run()

Run drains children on SIGCHLD. It is the only wait4 caller in the process.

func (*Reaper) Wait

func (r *Reaper) Wait(pid int) <-chan unix.WaitStatus

Wait registers pid and returns a channel that receives its exit status exactly once. Call it immediately after starting the child. If the child was already reaped (it exited before this call), the status is delivered immediately.

type Service

type Service struct {
	Name          ServiceName
	Description   string // optional human-readable summary for `sv`
	Startup       Command
	Shutdown      Command
	Ready         Command // optional readiness probe for daemons
	User          string  // optional unprivileged user to run the service as
	Provides      []ServiceType
	Needs         []ServiceType
	Type          serviceType
	RestartPolicy restartPolicy
	// contains filtered or unexported fields
}

func ParseConfig

func ParseConfig(r io.Reader) (*Service, error)

Parses a single config file into the services it provides

func (*Service) Restart

func (s *Service) Restart() error

Restart stops the service (ignoring a "not running" error) and starts it again.

func (*Service) Start

func (s *Service) Start() error

Start runs the service. A one-shot service runs to completion; a daemon is launched and then kept alive in the background by supervise() per its restart policy. Either way Start returns once the service is up (so StartServices can release its dependents), not when a daemon eventually exits.

func (*Service) Stop

func (s *Service) Stop() error

type ServiceName

type ServiceName string

type ServiceStatus

type ServiceStatus struct {
	Name        string    `json:"name"`
	Description string    `json:"description,omitempty"`
	State       string    `json:"state"` // run | down | fail | starting | done
	PID         int       `json:"pid,omitempty"`
	Since       time.Time `json:"since"` // start of the current run (zero if not running)
	Restarts    int       `json:"restarts"`
	Enabled     bool      `json:"enabled"` // starts at boot
}

ServiceStatus is a point-in-time snapshot of a service, reported to `sv` over the control socket.

type ServiceType

type ServiceType string

type Supervisor

type Supervisor struct {
	// contains filtered or unexported fields
}

Supervisor owns the services parsed from /etc/rc.d and provides name-based control (start/stop/restart/status) on top of the dependency-ordered startup and per-service supervision in service.go. It backs the `sv` control socket.

func NewSupervisor

func NewSupervisor(providers map[ServiceType][]*Service) *Supervisor

NewSupervisor indexes the parsed providers map by service name.

func (*Supervisor) Disable

func (sup *Supervisor) Disable(name string) error

Disable marks a service not to start at boot (writing a disabled marker). It does not stop it now — use `sv stop` for that.

func (*Supervisor) Enable

func (sup *Supervisor) Enable(name string) error

Enable marks a service to start at boot (removing its disabled marker). It does not start it now.

func (*Supervisor) List

func (sup *Supervisor) List() []ServiceStatus

List returns every service's status, ordered by name.

func (*Supervisor) OnStart

func (sup *Supervisor) OnStart(fn func(name string, err error))

OnStart registers a callback invoked by StartAll for each service as it starts (or fails to). It must be set before StartAll and is used by PID 1 to print per-service boot progress.

func (*Supervisor) OnStop

func (sup *Supervisor) OnStop(fn func(name string, err error))

OnStop registers a callback invoked by StopAll for each running service as it stops. It must be set before StopAll and is the shutdown counterpart to OnStart, used by PID 1 to print per-service shutdown progress.

func (*Supervisor) Reload

func (sup *Supervisor) Reload(name string) error

Reload re-reads the service's unit file from /etc/rc.d and restarts it with the updated definition. The supervisor otherwise holds the definition parsed at boot, so a changed Startup command (or any other unit field) is not picked up by Restart alone; Reload makes live reconfiguration possible without a reboot. Dependency wiring (Needs/Provides) for the boot ordering is not recomputed — only this service's own definition is refreshed.

If the unit wasn't known at boot, Reload registers it as a brand-new service and starts it (see register), so dropping a new /etc/rc.d/<name> file and running `sv reload <name>` brings it up live.

func (*Supervisor) Restart

func (sup *Supervisor) Restart(name string) error

func (*Supervisor) Start

func (sup *Supervisor) Start(name string) error

func (*Supervisor) StartAll

func (sup *Supervisor) StartAll()

StartAll brings up every enabled service, honouring Needs/Provides ordering. Disabled services are excluded entirely (their capabilities aren't advertised, so a dependent of a disabled service won't start either); they can still be started by hand with `sv start`.

func (*Supervisor) Status

func (sup *Supervisor) Status(name string) (ServiceStatus, error)

func (*Supervisor) Stop

func (sup *Supervisor) Stop(name string) error

func (*Supervisor) StopAll

func (sup *Supervisor) StopAll()

StopAll stops every running daemon, reporting each via onStop. It's the shutdown counterpart to StartAll. The daemons have no stop-order dependencies among them, so they're stopped concurrently — shutdown waits roughly the slowest service's stop grace rather than the sum. One-shot services have already run to completion, so there's nothing to stop.

type UI

type UI struct {
	// contains filtered or unexported fields
}

UI renders status lines to a writer, with colour and glyphs when that writer is a terminal. Its methods are safe for concurrent use, so service-start events reported from supervisor goroutines don't interleave on the console.

func NewUI

func NewUI(w io.Writer) *UI

NewUI binds a UI to w, detecting colour support from w.

func (*UI) Bold

func (u *UI) Bold(s string) string

Bold / Dim / Color expose the writer's colour scheme for inline use (table cells, names) so callers don't each re-implement the no-op-when-plain rule.

func (*UI) Colored

func (u *UI) Colored() bool

Colored is true when this UI emits ANSI colour.

func (*UI) Dim

func (u *UI) Dim(s string) string

func (*UI) Fail

func (u *UI) Fail(format string, args ...any)

Fail reports a step that failed (red cross).

func (*UI) Green

func (u *UI) Green(s string) string

func (*UI) OK

func (u *UI) OK(format string, args ...any)

OK reports a step that succeeded (green check).

func (*UI) Plain

func (u *UI) Plain(format string, args ...any)

Plain writes a message with no sigil.

func (*UI) Red

func (u *UI) Red(s string) string

func (*UI) ServiceState

func (u *UI) ServiceState(state string, width int) (dot, word string)

ServiceState maps a service state ("run", "down", "fail", "starting", "done") to a coloured status dot and the state word padded to width and coloured to match — green for running/done, red for failed, yellow for starting, dim for down. Used by `sv` to render its status table.

func (*UI) Step

func (u *UI) Step(format string, args ...any)

Step announces a top-level action (cyan ::).

func (*UI) Warn

func (u *UI) Warn(format string, args ...any)

Warn reports a non-fatal problem (yellow bang).

func (*UI) Yellow

func (u *UI) Yellow(s string) string

type Unmounter

type Unmounter func() error

func Mount

func Mount(mountOpts ...MountOption) (Unmounter, error)

Mount mounts list of mountOptions and returns a function to unmount them.

Directories

Path Synopsis
arp
cal
cat
cloudinit
Package cloudinit is a minimal cloud-init for GoNIX: at boot it discovers the instance's SSH keys, hostname and user-data from the platform and applies them, so a fresh image becomes a configured server with no baked-in secrets.
Package cloudinit is a minimal cloud-init for GoNIX: at boot it discovers the instance's SSH keys, hostname and user-data from the platform and applies them, so a fresh image becomes a configured server with no baked-in secrets.
cmp
cp
cut
datadisk
Package datadisk mounts the optional persistent data disk as a supervised one-shot service (started from /etc/rc.d/datadisk, Provides: data).
Package datadisk mounts the optional persistent data disk as a supervised one-shot service (started from /etc/rc.d/datadisk, Provides: data).
df
du
env
id
ip
killall
Package killall implements killall: send a signal to all processes matching a name exactly (by comm, as in the traditional psmisc tool).
Package killall implements killall: send a signal to all processes matching a name exactly (by comm, as in the traditional psmisc tool).
ln
ls
mv
network
Package network configures eth0 as a supervised service (started from /etc/rc.d/network): a static address when /etc/rc.conf sets IP, otherwise a DHCP client.
Package network configures eth0 as a supervised service (started from /etc/rc.d/network): a static address when /etc/rc.conf sets IP, otherwise a DHCP client.
nl
nohup
Package nohup implements nohup: run a program immune to hangups, with output redirected to nohup.out when stdout is a terminal.
Package nohup implements nohup: run a program immune to hangups, with output redirected to nohup.out when stdout is a terminal.
pgrep
Package pgrep implements pgrep and pkill: find (and optionally signal) processes by name.
Package pgrep implements pgrep and pkill: find (and optionally signal) processes by name.
ps
pwd
rm
scp
seq
setsid
Package setsid implements setsid: run a program in a new session, detached from the controlling terminal.
Package setsid implements setsid: run a program in a new session, detached from the controlling terminal.
sh
sshd
Package sshd runs the GoNIX SSH server as a standalone, supervised service (started from /etc/rc.d/sshd), rather than a goroutine inside init.
Package sshd runs the GoNIX SSH server as a standalone, supervised service (started from /etc/rc.d/sshd), rather than a goroutine inside init.
strace
go-strace only implements its syscall arg/ret decoding for amd64, so the real strace applet is amd64-only; strace_unsupported.go provides a stub elsewhere.
go-strace only implements its syscall arg/ret decoding for amd64, so the real strace applet is amd64-only; strace_unsupported.go provides a stub elsewhere.
sv
Package sv implements the `sv` service-control client: a thin front-end to the supervisor PID 1 runs, reached over the /run/sv.sock control socket.
Package sv implements the `sv` service-control client: a thin front-end to the supervisor PID 1 runs, reached over the /run/sv.sock control socket.
tac
tar
tau
tee
tr
tty
wc
wg
Package wg is a small WireGuard control applet for GoNIX.
Package wg is a small WireGuard control applet for GoNIX.
yes
Package cefhost is the shared CEF (Chromium) offscreen-rendering host used by both browser host roles:
Package cefhost is the shared CEF (Chromium) offscreen-rendering host used by both browser host roles:
Package cefipc is the shared transport contract between the GoNIX/macOS browser shell and its CEF rendering host: a memory-mapped frame buffer plus the constants both sides agree on.
Package cefipc is the shared transport contract between the GoNIX/macOS browser shell and its CEF rendering host: a memory-mapped frame buffer plus the constants both sides agree on.
Package gui is a tiny, backend-agnostic windowing contract: a resizable software framebuffer (an *image.RGBA painted by the application) plus pointer, keyboard and scroll input and a run loop.
Package gui is a tiny, backend-agnostic windowing contract: a resizable software framebuffer (an *image.RGBA painted by the application) plus pointer, keyboard and scroll input and a run loop.
Package wlui is a minimal, pure-Go, software-rendered Wayland window toolkit.
Package wlui is a minimal, pure-Go, software-rendered Wayland window toolkit.
swizzle
Package swizzle provides functions for converting between RGBA pixel formats.
Package swizzle provides functions for converting between RGBA pixel formats.
text
Package text is a minimal pure-Go text-rendering layer for wlui apps.
Package text is a minimal pure-Go text-rendering layer for wlui apps.
ui
Package ui provides shared theming and drawing helpers for GoNIX GUI apps built on wlui — the small, home-grown beginnings of a widget layer.
Package ui provides shared theming and drawing helpers for GoNIX GUI apps built on wlui — the small, home-grown beginnings of a widget layer.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL