3.1 Services

A service is the primary unit of management: a definition in the registry, a runtime state, a Security Descriptor, and at most one running main process. Definitions live under Machine\System\Services\<name>, where the key name is the service name. peinit reads them at Phase 2 boot and on an explicit reload-config.

3.1.1 Names #

A service name is 1 to 128 bytes drawn from [A-Za-z0-9._-]. Any other byte makes the name invalid.

Two exclusions are deliberate. / is out because names map directly onto cgroup identifiers (§5.1) and onto registry key names, and a name containing a separator would mean something different in each. : is reserved for peinit's own synthetic naming.

3.1.2 The two types #

3.1.2.1 Simple #

A long-running daemon. peinit forks, installs a token, and execs the binary; the process is the service. When it exits, the service has stopped. This is the default and covers nearly everything — registryd, authd, sshd, application services.

Readiness comes from the Readiness field. Notify, the default, waits for READY=1. Alive treats the process as ready the moment it exists.

The service goes Active on readiness and stays Active until the process exits or something stops it.

3.1.2.2 Oneshot #

A run-to-completion task: database initialisation, a schema migration, a directory that has to exist. peinit forks, installs a token, execs, and waits for the exit.

Readiness is ignored. A Oneshot's readiness is always "it exited successfully", because READY=1 is meaningless from a process whose job is to finish. Success means exit code 0, or any code listed in SuccessExitCodes.

The differences from Simple are:

  • A successful exit goes to Completed. With RemainAfterExit=1 it stays there; without, it passes through Completed to release dependents and then goes Inactive.
  • A non-zero exit goes to Failed.
  • ExecStartPost runs after the successful exit rather than after a readiness signal, and does not run at all if the Oneshot failed.
  • StartTimeout covers the entire execution, from the first pre-hook to the process exiting.

RemainAfterExit matters when the Completed state itself is the useful information — so a status query shows a migration as finished rather than as inactive.

3.1.3 Forking daemons #

peinit does not support them. A service that double-forks to daemonise itself is working around a problem that does not exist when the service manager tracks the process it spawned, and peinit tracks its child through a pidfd obtained at fork. There is no MAINPID=, and no way to point supervision at a different process.

A legacy binary that insists on double-forking is wrapped by whoever packages it — a script with a --no-daemon flag, typically. That is a packaging concern.

Edit this page